clarify exceptions
diff --git a/xos/cord/models.py b/xos/cord/models.py
index 66c135e..6fe605c 100644
--- a/xos/cord/models.py
+++ b/xos/cord/models.py
@@ -7,6 +7,7 @@
 from django.db.models import Q
 from operator import itemgetter, attrgetter, methodcaller
 import traceback
+from xos.exceptions import *
 
 """
 import os
@@ -105,7 +106,7 @@
         if self.vcpe is None:
             vcpeServices = VCPEService.get_service_objects().all()
             if not vcpeServices:
-                raise ConfigurationError("No VCPE Services available")
+                raise XOSConfigurationError("No VCPE Services available")
 
             vcpe = VCPETenant(provider_service = vcpeServices[0],
                               subscriber_tenant = self)
@@ -125,8 +126,10 @@
             self.vcpe = None
 
     def save(self, *args, **kwargs):
+        self.validate_unique_service_specific_id()
+
         if not getattr(self, "caller", None):
-            raise TypeError("VOLTTenant's self.caller was not set")
+            raise XOSProgrammingError("VOLTTenant's self.caller was not set")
         super(VOLTTenant, self).save(*args, **kwargs)
         self.manage_vcpe()
 
@@ -274,7 +277,7 @@
             self.sliver = None
         if self.sliver is None:
             if not self.provider_service.slices.count():
-                raise ConfigurationError("The VCPE service has no slicers")
+                raise XOSConfigurationError("The VCPE service has no slicers")
 
             node =self.pick_node()
             sliver = Sliver(slice = self.provider_service.slices.all()[0],
@@ -305,7 +308,7 @@
         if self.vbng is None:
             vbngServices = VBNGService.get_service_objects().all()
             if not vbngServices:
-                raise ConfigurationError("No VBNG Services available")
+                raise XOSConfigurationError("No VBNG Services available")
 
             vbng = VBNGTenant(provider_service = vbngServices[0],
                               subscriber_tenant = self)
@@ -326,7 +329,7 @@
 
     def save(self, *args, **kwargs):
         if not getattr(self, "caller", None):
-            raise TypeError("VCPETenant's self.caller was not set")
+            raise XOSProgrammingError("VCPETenant's self.caller was not set")
         super(VCPETenant, self).save(*args, **kwargs)
         self.manage_sliver()
         self.manage_vbng()
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index 48d1677..afb4949 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -1,6 +1,7 @@
 from django.db import models
 from core.models import PlCoreBase,SingletonModel,PlCoreBaseManager
 from core.models.plcorebase import StrippedCharField
+from xos.exceptions import *
 import json
 
 class Service(PlCoreBase):
@@ -92,4 +93,14 @@
     def get_tenant_objects(cls):
         return cls.objects.filter(kind = cls.KIND)
 
+    # helper function to be used in subclasses that want to ensure service_specific_id is unique
+    def validate_unique_service_specific_id(self):
+        if self.pk is None:
+            if self.service_specific_id is None:
+                raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={"service_specific_id": "cannot be none"})
+
+            conflicts = self.get_tenant_objects().filter(service_specific_id=self.service_specific_id)
+            if conflicts:
+                raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={"service_specific_id": "duplicate key"})
+