Appearance
Error codes
The Matrix protocol uses a small, machine-readable error-code catalog so that callers can pattern-match on errors without parsing English. The codes mirror gRPC's Status codes, which keeps the gRPC bridge mechanical.
Status: target state, partial. Many actors today return only
{ ok: false, error: <message> }without acodefield. New code should setcode. The catalog below is the convergence target.
The catalog
| Code | gRPC analog | HTTP status | When to use |
|---|---|---|---|
OK | OK | 200 | success — though usually omitted (just ok: true) |
NOT_FOUND | NOT_FOUND | 404 | the requested record does not exist |
INVALID_ARGUMENT | INVALID_ARGUMENT | 400 | payload missing required field, malformed shape, validation failure |
UNAUTHENTICATED | UNAUTHENTICATED | 401 | no session / invalid token |
PERMISSION_DENIED | PERMISSION_DENIED | 403 | authenticated, but principal not authorized for this op |
ALREADY_EXISTS | ALREADY_EXISTS | 409 | unique-key collision on a write |
FAILED_PRECONDITION | FAILED_PRECONDITION | 409 | op cannot run in the current state (e.g., a Host Service op invoked when the Host is not configured to handle it) |
RESOURCE_EXHAUSTED | RESOURCE_EXHAUSTED | 429 | rate limit hit, quota exceeded |
DEADLINE_EXCEEDED | DEADLINE_EXCEEDED | 504 | request timed out |
UNAVAILABLE | UNAVAILABLE | 503 | upstream service unreachable (NATS down, dependency offline) |
INTERNAL | INTERNAL | 500 | unexpected internal failure (default for thrown exceptions) |
Per-actor declaration
Actors document their error specs through static errorSpecs (MatrixActor.ts:265):
typescript
static errorSpecs = {
'registry.resolve': [
{ code: 'NOT_FOUND', description: 'No live providers for the logical mount.' },
{ code: 'INVALID_ARGUMENT', description: 'logicalMount missing or empty.' },
],
'registry.register': [
{ code: 'INVALID_ARGUMENT', description: 'logicalMount or providerRuntimeId missing.' },
],
};$introspect { depth: 'full' } returns this; protocol gateways surface it (gRPC error details, OpenAPI responses, MCP error annotations).
Examples from running code
| Reply text | Suggested code |
|---|---|
'gateway.http.resolve requires a non-empty pathname' | INVALID_ARGUMENT |
'No Host runtime webapp route matched the request' | NOT_FOUND |
'gateway.http.request only supports GET and HEAD' | INVALID_ARGUMENT (HTTP 405) |
'runtimes.reconcile is not available in daemonless Host mode' (legacy literal; the retired matrixd path is disabled — Host Service is the supported path) | FAILED_PRECONDITION |
'request timed out after 5000ms' (transport-side) | DEADLINE_EXCEEDED |
These are the patterns. Today the actors emit only the error text; adding the code is a per-package backfill.
Code vs HTTP status
When the op is exposed via the HTTP gateway, the statusCode field on the error payload sets the HTTP response status. The code field is internal/structural; the statusCode is the HTTP-mapping. Both are optional; consistent code with the table above keeps them in sync.
Code vs message
code: stable across versions, machine-matchable, never localized.error: human-readable, may evolve message text without breaking callers, may include op-specific values ("expectedsymbol, got''").details: structured op-specific data the caller can use programmatically (e.g., the field name that failed validation).
What code is NOT
- It is not free-form. Callers pattern-match on the catalog above. Custom codes belong in
details.subcodeif needed. - It is not localized. Pass localized text in
error; keepcodeASCII-uppercase. - It is not authoritative for HTTP status. Set
statusCodeexplicitly if your op maps to HTTP.
Adding a new code
The catalog is intentionally small. Before introducing a new top-level code:
- Check the gRPC
Statuscodes — if a match exists, use it. - If the situation is op-specific (e.g., "wrong git branch", "stale Device link"), use the closest catalog code and put the specific shape in
details. - If a truly new code is warranted, propose it in
WORKSTREAMS/core-and-packaging/and reference this page.
Convergence on the small catalog is the goal — every new code raises the cost for callers and gateway adapters.
See also
- Error envelope — wire shape.
- Envelope schemas — JSON Schema with the code enum.
- Timeouts — when
DEADLINE_EXCEEDEDapplies. - gRPC bridge — gRPC mapping.