Territory management deployment fails in cloud org due to missing custom metadata dependencies

Deploying territory models and assignments from sandbox to production fails with missing dependency error. We created a custom territory model with 15 territories organized by region and product line. The model uses custom metadata types to define territory rules (TerritoryRule__mdt) and assignment criteria (TerritoryAssignment__mdt).

SFDX deployment error:


Error: Territory2Model 'EMEA_Sales_Model'
Problem: Custom metadata type 'TerritoryRule__mdt' not found

The custom metadata types exist in sandbox and are included in our SFDX project under force-app/main/default/customMetadata/. The sfdx-project.json includes the path. We tried deploying custom metadata first, then territory models, but still get the dependency error. The missing custom metadata blocks our territory rollout. How do we properly sequence SFDX retrieve/deploy for territory models with custom metadata dependencies?

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:

  1. Store the metadata in the database
  2. Update the metadata cache
  3. Rebuild the EntityDefinition index
  4. 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:

  1. Query EntityDefinition to confirm metadata type is indexed: `SELECT QualifiedApiName FROM EntityDefinition WHERE QualifiedApiName = ‘TerritoryRule__mdt’
  2. Check field definitions are deployed: `sfdx force:source:deploy -m CustomField:TerritoryRule__mdt.Region__c
  3. 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.

Territory models have strict deployment order requirements. You need to deploy in this sequence: 1) Custom Metadata Type definitions (.object-meta.xml files), 2) Custom Metadata records (.md-meta.xml files), 3) Territory Model structure, 4) Territory assignments. Try breaking your deployment into separate commands for each layer instead of deploying everything at once.

Check your SFDX project structure carefully. Custom Metadata Type definitions should be in force-app/main/default/objects/TerritoryRule__mdt/ with the object definition file. Custom Metadata records should be in force-app/main/default/customMetadata/. If the structure is wrong, SFDX won’t recognize the dependency chain and deploys in the wrong order.

I verified the structure - we have TerritoryRule__mdt.object-meta.xml in the objects folder and individual records like TerritoryRule.EMEA_North.md-meta.xml in customMetadata folder. The sfdx-project.json has both paths listed. When I deploy just the custom metadata types first using ‘sfdx force:source:deploy -m CustomObject:TerritoryRule__mdt’, it succeeds. But when I then deploy the territory model, it still claims the metadata type doesn’t exist. Is there a cache timing issue?

Tested this on a Spring '24 sandbox-to-production deployment: staging TerritoryRule__mdt object-meta.xml before CustomMetadata records eliminated the ‘Custom metadata type not found’ error entirely.

Yes, there’s definitely a metadata cache delay. After deploying custom metadata types, the target org needs time to index them before they’re available for reference by other components. Wait at least 5-10 minutes between deploying the metadata type definition and deploying components that reference it. You can also try querying the custom metadata in production via Developer Console to confirm it’s fully available before deploying the territory model.

Another thing to check - are your territory model XML files explicitly referencing the custom metadata type? Territory2Model metadata should have field references like ‘TerritoryRule__mdt.Region__c’. If the reference format is wrong, SFDX can’t resolve the dependency even if the metadata type exists. Retrieve a working territory model from another org to compare the XML structure.