Zendesk Drift Issue Code Reference
Every issue code, every safe action, and every blocked_reason that g-gremlin zendesk drift can emit. 12 issue codes (6 org, 4 user, 2 ticket). 4 safe Zendesk-side actions. 7 blocked reasons. Use this page to map a finding in exceptions_by_account.csv or apply_receipt.json to its resolution path.
Published April 17, 2026 - Canonical reference for the Zendesk drift audit
Short answer
Three lists. Twelve issue codes, four safe actions, seven blocked reasons.
- 6 org-level issues (1 critical, 2 high, 3 medium). 2 are auto-prepared as safe actions; 4 are review-only.
- 4 user-level issues (1 high, 3 medium). 2 are safe-to-apply; 2 are review-only.
- 2 ticket-level issues. Both are detection-only. Ticket mutation is out of scope in v1.
- 4 safe actions total: set_org_external_id, add_org_domain, assign_user_to_org, move_user_to_org.
- Blocked reasons land in apply_receipt.json. No action is ever silently dropped.
The 12 Zendesk drift issue codes
Grouped by scope: 6 org, 4 user, 2 ticket. Each row names the code, its risk, its disposition, the safe action (when applicable), the definition, and the evidence that triggers it.
Org (6)
org_duplicate_external_id
critical review-onlyTwo or more Zendesk organizations share the same external_id for one Salesforce account. Blocks every downstream user and ticket decision for that account.
Evidence: Multiple Zendesk orgs with identical external_id == sf_account_id.
Resolution guideorg_missing_external_id
high safe-to-applyset_org_external_idA unique domain-based org candidate has a blank external_id. Gremlin can set it safely to the Salesforce account id.
Evidence: Unique domain-based org candidate plus blank external_id on the target org.
Resolution guideorg_external_id_conflict
high review-onlyA likely org candidate has a nonblank external_id that conflicts with the expected Salesforce account. Resolve in Zendesk; Gremlin never overwrites a conflicting id.
Evidence: Unique domain candidate plus conflicting nonblank external_id.
org_missing_expected_domain
medium safe-to-applyadd_org_domainThe resolved org is missing one or more expected domains from the Salesforce effective domain set. Safe to attach when the collision precheck passes.
Evidence: Unique resolved org plus one or more expected domains absent from the org domain list.
org_domain_attached_elsewhere
critical review-onlyAn expected domain is already attached to another Zendesk org. Blocked with reason domain_belongs_to_other_org; Gremlin never steals domains.
Evidence: Precheck against all org domains shows the domain belongs to another org.
Resolution guideaccount_missing_zendesk_org
medium review-onlyA Salesforce account has no unique external_id match and no safe domain-resolved target org. Create the org manually, then re-audit.
Evidence: No unique external-ID match and no safe domain-resolved target org.
Resolution guideUser (4)
user_missing_expected_membership
high safe-to-applyassign_user_to_orgA user maps deterministically to an account but is not a member of the expected org. Gremlin adds the membership. It does not change the default org.
Evidence: Non-personal deterministic account resolution plus membership set lacks target org.
user_default_org_not_expected
medium safe-to-applymove_user_to_orgUser is already a member of the expected org, but the default org differs. Gremlin promotes the existing target membership to default. It does not add or remove memberships.
Evidence: Membership includes target org, but user.organization_id is not the target.
Resolution guideuser_resolution_blocked_duplicate_external_id
high review-onlyThe user’s expected account depends on an account/org mapping blocked by duplicate external_ids upstream. Resolve the org-level duplicate first.
Evidence: Upstream org_duplicate_external_id.
Resolution guideuser_domain_ambiguous
medium review-onlyA non-personal email domain maps to multiple candidate accounts or orgs. Personal email domains are suppressed from user drift detection entirely.
Evidence: Domain collision across Salesforce accounts or unresolved org ambiguity.
Ticket (2) - detection only
ticket_org_mismatch
medium review-onlyA ticket’s organization_id does not match the requester’s deterministically resolved expected org. Detection only; ticket mutation is out of scope.
Evidence: Requester resolution plus ticket org differs or is blank.
ticket_resolution_blocked_duplicate_external_id
medium review-onlyTicket attribution cannot be trusted because the requester’s account resolution is blocked upstream. Detection only.
Evidence: Upstream org_duplicate_external_id.
Resolution guideThe 4 safe Zendesk-side actions
Each action lists its preconditions (all must hold) and the conditions under which Gremlin explicitly blocks it.
set_org_external_id
Set a blank Zendesk org external_id to the Salesforce account id.
Preconditions
- Exactly one target Zendesk org is resolved.
- Target org external_id is blank.
- No other Zendesk org already uses the intended Salesforce account id.
- Account is not blocked by duplicate external-id ambiguity.
Blocked when
- Target org already has a conflicting nonblank external_id.
- Another org already uses the intended Salesforce account id.
add_org_domain
Append one missing expected domain to the resolved Zendesk org.
Preconditions
- Exactly one target Zendesk org is resolved.
- Domain is in the account’s effective domain set.
- Domain is not already present on the target org.
- Domain is not a personal/consumer email domain.
- Account is not blocked by duplicate external-id ambiguity.
- Precheck confirms the domain is not attached to another Zendesk org.
Blocked when
- Domain belongs to another org (blocked_reason: domain_belongs_to_other_org).
- Account is ambiguous.
- Target org cannot be uniquely resolved.
assign_user_to_org
Add a missing organization membership for a user. Does not change the default org.
Preconditions
- User maps deterministically to one expected account and one expected Zendesk org.
- Account is not blocked by duplicate external-id ambiguity.
- User is not already a member of the target org.
- User match did not depend on a personal-email-domain rule.
Blocked when
- Account ambiguous (duplicate_external_id).
- User domain is ambiguous across multiple accounts.
- User is already a member of the target org (no action needed).
move_user_to_org
Make an existing target membership the user’s default org. Does not add or remove membership.
Preconditions
- User maps deterministically to one expected account and one expected Zendesk org.
- Account is not blocked by duplicate external-id ambiguity.
- User is already a member of the target org.
- Current default org differs from the target org.
Blocked when
- User is not a member of the target org (would require assign_user_to_org instead).
- Account ambiguous (duplicate_external_id).
Blocked reasons in apply_receipt.json
When a prepared action is not applied, Gremlin records exactly why. These are the values you will see in the blocked, skipped, or failed rows of apply_receipt.json.
| blocked_reason | Applies to | Meaning and resolution |
|---|---|---|
| duplicate_external_id | every action on the affected account | The Salesforce account resolves to more than one Zendesk org. No safe action is prepared until the duplicate is resolved in Zendesk. Fix duplicate external_id in Zendesk. |
| domain_belongs_to_other_org | add_org_domain | The domain Gremlin wanted to attach is already attached to a different Zendesk org. Detach manually, then re-audit. Zendesk domain collision between organizations. |
| user_domain_ambiguous | assign_user_to_org and move_user_to_org | A non-personal email domain maps to multiple candidate accounts or orgs. Resolve upstream in Salesforce or Zendesk. |
| precondition_changed_user_already_member | assign_user_to_org | Between audit and apply, the user was added to the target org. Gremlin skips the action with an explicit reason. |
| precondition_changed_external_id_now_set | set_org_external_id | Between audit and apply, the target org external_id was set by another system. Gremlin skips without overwriting. |
| precondition_changed_domain_already_present | add_org_domain | Between audit and apply, the target org already carries the expected domain. No action needed. |
| failed_rate_limited | any live-apply action | Bounded exponential backoff on HTTP 429 was exhausted. The action is recorded with failure code failed_rate_limited and does not silently drop. |
No action is ever silently dropped. Blocked, skipped, and failed rows all carry explicit reason codes.
FAQ
How many issue codes does g-gremlin zendesk drift emit?
Twelve. Six org-level (org_duplicate_external_id, org_missing_external_id, org_external_id_conflict, org_missing_expected_domain, org_domain_attached_elsewhere, account_missing_zendesk_org), four user-level (user_missing_expected_membership, user_default_org_not_expected, user_resolution_blocked_duplicate_external_id, user_domain_ambiguous), and two ticket-level (ticket_org_mismatch, ticket_resolution_blocked_duplicate_external_id). The ticket codes are detection-only and never generate write actions.
Which issue codes are safe-to-apply?
Four. org_missing_external_id is auto-prepared as set_org_external_id. org_missing_expected_domain is auto-prepared as add_org_domain when the collision precheck passes. user_missing_expected_membership is auto-prepared as assign_user_to_org. user_default_org_not_expected is auto-prepared as move_user_to_org. Every other issue code stays review-only by design.
What are the 4 safe Zendesk-side actions in v1?
set_org_external_id (set a blank Zendesk org external_id to the Salesforce account id), add_org_domain (attach a missing expected domain to the resolved org), assign_user_to_org (add a missing organization membership for a user), and move_user_to_org (promote an existing target membership to default). Nothing else is written live. No ticket mutation, no org create/merge/delete, no Salesforce writes.
What does blocked_reason mean in apply_receipt.json?
It is the explicit reason a prepared action was not applied. Common values are duplicate_external_id, domain_belongs_to_other_org, user_domain_ambiguous, and the precondition_changed_* family for actions that became unsafe between audit and apply. failed_rate_limited records exhausted backoff on HTTP 429.
Why does Gremlin keep duplicate_external_id issues review-only?
Because picking the wrong surviving org would quietly corrupt the customer graph. The tool cannot deterministically decide which duplicate is the real org. It needs a human with Zendesk context. This is why org_duplicate_external_id, user_resolution_blocked_duplicate_external_id, and ticket_resolution_blocked_duplicate_external_id are all review-only.
Are personal email domains treated as drift?
No. gmail.com, outlook.com, yahoo.com, icloud.com, hotmail.com, protonmail.com, and similar consumer domains are suppressed from domain-based user drift detection. End-users on those domains are only linked through a deterministic path like an existing membership on a uniquely resolved Zendesk org. They may appear in trace output with suppression_reason = personal_email_domain_suppressed but do not generate domain-drift issues.
Does Gremlin ever overwrite an existing external_id or domain?
No. set_org_external_id requires a blank target external_id. add_org_domain requires a successful collision precheck proving the domain is not attached to another org. When those preconditions fail, the action is blocked and recorded in apply_receipt.json with an explicit reason.
What does Gremlin never do in v1?
Never writes to Salesforce. Never mutates Zendesk tickets. Never creates, merges, or deletes Zendesk organizations. Never removes organization memberships. Never bypasses caps. Never applies live without --apply and a matching --confirm-plan-hash. Never uses fuzzy or LLM-driven matching in the apply path.
Related Zendesk drift pages
Salesforce and Zendesk integration pillar
The audit-first integration contract. Start here if you are new to g-gremlin zendesk drift.
Open pageZendesk drift playbook
Operator execution log: Slack message, prompt, audit, review, dry-run, apply.
Open pageAudit Zendesk and Salesforce sync from the CLI
The focused CLI walkthrough for the drift audit workflow.
Open pageFix duplicate external_id in Zendesk
The critical blocker: two orgs share the same external_id.
Open pageLink a Zendesk organization to a Salesforce account
The safe-to-apply path for org_missing_external_id.
Open pageZendesk domain collision between organizations
What to do when domain_belongs_to_other_org blocks add_org_domain.
Open pageFix wrong default organization in Zendesk
The safe-to-apply fix for user_default_org_not_expected.
Open pageSalesforce Zendesk comparison
Native sync vs iPaaS vs audit-first CLI, side by side.
Open pageKeep the conversation going
These pages are meant to help operators solve real problems. If you want the next guide, grab the low-friction option. If you need the implementation, not just the guide, book time.
Get the next guide when it ships
I publish architecture guides grounded in real implementations. No generic AI filler.
Use your work email so I can keep the list useful and relevant.
Need the implementation, not just the guide?
Book a 15-minute working session with Mike right on his calendar. Tooling, consulting, or a mix of both is fine.
Open Mike's calendarIf you want me to come in with context, leave your email and a short note before the call.