You’re hitting a complex dependency chain that requires careful sequencing across all three focus areas:
1. Custom Metadata Dependencies (Root Cause):
Custom Metadata Types have a two-tier structure that MUST deploy in order:
- Tier 1: CustomObject definition (TerritoryRule__mdt.object-meta.xml) - Defines the metadata type schema
- Tier 2: CustomMetadata records (TerritoryRule.RecordName.md-meta.xml) - Actual data records
Territory models reference BOTH tiers. The error ‘Custom metadata type not found’ means Tier 1 isn’t fully indexed in the target org when the territory model tries to validate.
2. Territory Model Deployment (Sequencing Strategy):
Territory2Model metadata has dependencies on:
- Custom Metadata Types (for rule definitions)
- Custom Fields on Account/Opportunity (for assignment criteria)
- User records (for territory assignments)
Deploy in this exact order:
# Step 1: Deploy custom metadata type definitions
sfdx force:source:deploy -m CustomObject:TerritoryRule__mdt,CustomObject:TerritoryAssignment__mdt -u prodOrg
# Step 2: Wait for indexing (critical!)
sleep 300
# Step 3: Deploy custom metadata records
sfdx force:source:deploy -m CustomMetadata -u prodOrg
# Step 4: Deploy territory model structure
sfdx force:source:deploy -m Territory2Model:EMEA_Sales_Model -u prodOrg
# Step 5: Deploy territory assignments
sfdx force:source:deploy -m Territory2 -u prodOrg
3. SFDX Retrieve/Deploy Usage (Best Practices):
Retrieve Complete Dependency Chain:
sfdx force:source:retrieve -m Territory2Model:EMEA_Sales_Model
sfdx force:source:retrieve -m Territory2
sfdx force:source:retrieve -m CustomObject:TerritoryRule__mdt
sfdx force:source:retrieve -m CustomMetadata
Project Structure (Critical):
force-app/main/default/
├── objects/
│ ├── TerritoryRule__mdt/
│ │ ├── TerritoryRule__mdt.object-meta.xml
│ │ └── fields/
│ │ ├── Region__c.field-meta.xml
│ │ └── ProductLine__c.field-meta.xml
│ └── TerritoryAssignment__mdt/
│ └── TerritoryAssignment__mdt.object-meta.xml
├── customMetadata/
│ ├── TerritoryRule.EMEA_North.md-meta.xml
│ ├── TerritoryRule.EMEA_South.md-meta.xml
│ └── TerritoryAssignment.Default.md-meta.xml
├── territory2Models/
│ └── EMEA_Sales_Model.territory2Model-meta.xml
└── territory2/
├── EMEA_North.territory2-meta.xml
└── EMEA_South.territory2-meta.xml
sfdx-project.json Configuration:
{
"packageDirectories": [
{
"path": "force-app",
"default": true
}
],
"sourceApiVersion": "59.0"
}
Complete Deployment Script:
#!/bin/bash
TARGET_ORG="prodOrg"
# Deploy custom metadata type definitions first
echo "Deploying custom metadata types..."
sfdx force:source:deploy -p force-app/main/default/objects/TerritoryRule__mdt -u $TARGET_ORG --wait 10
sfdx force:source:deploy -p force-app/main/default/objects/TerritoryAssignment__mdt -u $TARGET_ORG --wait 10
# Wait for metadata indexing
echo "Waiting for metadata cache refresh..."
sleep 300
# Verify custom metadata types are available
echo "Verifying metadata types..."
sfdx force:data:soql:query -q "SELECT Id, DeveloperName FROM EntityDefinition WHERE QualifiedApiName = 'TerritoryRule__mdt'" -u $TARGET_ORG
# Deploy custom metadata records
echo "Deploying custom metadata records..."
sfdx force:source:deploy -p force-app/main/default/customMetadata -u $TARGET_ORG --wait 10
# Deploy territory model
echo "Deploying territory model..."
sfdx force:source:deploy -m Territory2Model:EMEA_Sales_Model -u $TARGET_ORG --wait 10
# Deploy territory assignments
echo "Deploying territories..."
sfdx force:source:deploy -p force-app/main/default/territory2 -u $TARGET_ORG --wait 10
echo "Deployment complete!"
Why the 5-Minute Wait Matters:
When you deploy a CustomObject (metadata type definition), Salesforce must:
- Store the metadata in the database
- Update the metadata cache
- Rebuild the EntityDefinition index
- Make it available for cross-references
This process isn’t instant. Territory models validate their references during deployment. If you deploy too quickly, the metadata type exists in the database but isn’t yet in the cross-reference cache, causing ‘not found’ errors.
Troubleshooting:
If deployment still fails after waiting:
- Query EntityDefinition to confirm metadata type is indexed:
`SELECT QualifiedApiName FROM EntityDefinition WHERE QualifiedApiName = ‘TerritoryRule__mdt’
- Check field definitions are deployed:
`sfdx force:source:deploy -m CustomField:TerritoryRule__mdt.Region__c
- Verify territory model XML has correct references (open .territory2Model-meta.xml and check field references match exactly)
This dependency chain is why many orgs use unlocked packages for territory models - packages handle dependency ordering automatically.
This draft is based on general Salesforce knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.