TEASEDocs
ProductsLinkDomains

Troubleshooting

Common Domains failures, why they happen, and where to check.

A domain sits in pending_dns for weeks

Symptom: The domain never leaves pending_dns, no matter how long you wait.

Cause: The A record doesn't point at the server, or it resolves to an internal/blocked address — the SSRF guard treats that identically to "not pointing here yet" and refuses to provision against it.

Check: provisioning_error on the domain row, and check_dns() in core/domain_provision.py.

DNS looks right but verify never turns green

Symptom: Your DNS host confirms the CNAME/A record is correct, but /verify still returns pending_dns.

Cause: For an external domain (not on our Cloudflare zone), the CNAME/A match alone isn't enough — the TXT ownership token at _tease-challenge.<host> is missing or stale, so domain control was never actually proven.

Check: connect_service.verify_domaincheck_txt_token (core/domains/connect_service.py, core/domains/dns_verify.py) — the issue comes back with class: "dcv_missing".

409 on delete or rename (domain carries public addresses / has QR codes)

Symptom: Deleting or renaming an address fails with a 409 even though it looks unused.

Cause: The domain is still a live carrier — either another channel's public address is an alias pointing through it, or QR codes have been printed referencing it.

Check: domain_safety.assert_domain_host_mutable (api/admin/domain_safety.py).

409 domain_busy on an ordinary edit

Symptom: A routine edit to a domain fails with 409 domain_busy.

Cause: A concurrent operation already holds the advisory lock on this domain (or a domain in the same rotation chain). The lock waits up to 5 seconds before giving up — this is a real in-flight conflict, not a stuck state.

Check: lock_domain_mutations / LOCK_WAIT_SECONDS (core/domain_mutation_lock.py). If you just added the domain, a certificate may still be issuing (up to ~2 minutes) — that alone can trigger this.

Rotation refuses to start

Symptom: Moving to a reserve domain fails immediately with 409 reserve_not_ready.

Cause: Preflight found a blocker on the reserve — wrong ownership scope, objects already on it, or it isn't TLS-ready yet.

Check: preflight_domain_rotation / _assert_rotation_ready (core/domain_rotation.py) — see Move off a burned domain for the full checklist.

A domain row is stuck "provisioning" forever

Symptom: The domain shows provisioning indefinitely, with no error and no progress.

Cause: The backend crashed mid-call to the provisioning helper. The background poller only revives a row like this after 2× the helper's own timeout, to avoid racing a helper call that's still genuinely running.

Check: should_retry_pending (core/domain_provision.py).

What's next

Still stuck? See API reference gaps in Domains for endpoints not covered above, or Domains for the full task list.

On this page