Error catalog¶
Every trustmint factory-surface error is a stable THM-NNNNN code returned in an
application/problem+json body. This page is a front door — the authoritative,
machine-readable catalog lives in the repo and is generated, so this page links it
rather than copying it.
Source of truth (do not hand-edit)¶
Artifact |
Use |
|---|---|
|
Human-readable code reference (every code: status, title, description) |
|
Machine-readable form — what the SDK typed-error surface is generated from |
Both are generated from services/thingmake/internal/api/errorTable by
services/thingmake/cmd/error-catalog-gen. The CI drift-gate rejects any hand-edit. If
you think a code is wrong, fix the source table — not the catalog.
The THM-NNNNN code scheme¶
Codes are bucketed by domain: the leading digits identify the bucket, so THM-2xxxx
is factory-auth, THM-5xxxx is the state-changes feed, and so on. The authoritative
bucket list is the catalog’s Reservations table — buckets are generated and the set
grows, so read the catalog rather than memorizing a count.
At the time of writing the catalog reserves these domain buckets:
Bucket |
Domain |
Cross-reference |
|---|---|---|
1 |
foundation-auth |
JWT bearer auth on registration |
2 |
factory-auth |
AK/SK signing on registration |
3 |
registrar-lifecycle |
registrar approval / provisioning runs |
4 |
thing-state-machine |
illegal-transition / wrong-state (Thing lifecycle) |
5 |
state-changes-feed |
cursor polling on webhooks |
6 |
subscriptions |
webhook subscription rules on webhooks |
7 |
identity-blacklist |
the |
8 |
trust-anchor |
trust-anchor delivery to the factory backend |
9 |
internal-cross-domain-reserved |
reserved (no public codes yet) |
Bucket 2 — factory-auth covers inbound dispatch credential verification on every non-registration call (see registration). The dispatch credential is a Phase 45 workload-identity Bearer (an RS256 JWT carrying
iss,aud,expand akid), verified against the DotID token-exchange JWKS — it is no longer anFGAI-HMAC-SHA256signature. The codes are unchanged; what each one now means is:
Code
Dispatch failure mode
THM-20110
MISSING_HEADER— noAuthorizationheader at all
THM-20120
INVALID_SIGNATURE— the token does not verify, or does not bind here (audis another factory,issis not the realm, the signing algorithm is not an allowed RSA variant)
THM-20130
EXPIRED—expis in the past beyond the verifier’s clock-skew leeway
THM-20140
UNKNOWN_KEY— the presentedkidresolves to no key in the trusted JWKS. (This is what an unregistered access-key id became: same fact about the caller — you presented a key I do not know — so it keeps the same code.)
THM-20150
REPLAY— NOT EMITTED on the dispatch face. See below.⚠️
THM-20150no longer applies to inbound dispatches, and its absence is deliberate. A Bearer is replayable by construction: it authorises many calls to its audience and resource for its whole lifetime, so a legitimate second dispatch and a replay are the same bytes in the same position and no predicate separates them. Refusing on reuse would refuse valid traffic. Replay is therefore bounded rather than refused — short token TTL plusaud/resourcebinding — and reuse is recorded (not rejected) for audit. Do not treat a successful re-send of the same token as a contract violation, and do not expectTHM-20150on this path. The code remains in the catalog; it is simply not produced here.
THM-20100(factory-auth-failed) is the generic fallback for an unclassified verification failure. These codes are stable; this mapping is a navigation aid — the authoritative descriptions live in the generated catalog.Two codes in this bucket are 503, not 401, because your credential was never evaluated. Do not re-sign in response to either:
Code
Meaning
What to do
THM-20210the signature verifier could not be reached
retry after a short backoff
THM-20220the service’s own credential to the verifier was refused
report it — this is a server-side defect, not yours
Bucket 7 — identity-blacklist backs the
/provisioning/v1/identity-blacklist*endpoint group (see the API reference). Its codes cover blacklist lookups (THM-70100), delta-cursor handling (THM-70110malformed,THM-70120older than 72h → full-sync), and snapshot-not-ready (THM-70130).
Bucket 8 — trust-anchor backs trust-anchor delivery on the ACTIVATE saga leg. Its codes are
THM-TRUST-ANCHOR-FETCH-FAILED(503),THM-TRUST-ANCHOR-MALFORMED(502), andTHM-TRUST-ANCHOR-REJECTED(422). See Trust-anchor delivery §5.
This table is a navigation aid, not the source of truth: if a bucket is added upstream
it appears in the catalog’s Reservations table first. Always confirm against
thingmake-error-catalog.md.
How the SDKs use it¶
Both SDKs ship a generated typed-error surface built from thingmake-error-catalog.json.
On any 4xx/5xx they parse the problem body, look up the THM-NNNNN code, and return a
typed error (errors.Is(err, thingmake.ErrCode...) in Go, except ...Error in Python).
See the SDK quickstart.