ORK Errors Reference
ORK nodes report errors through a structured, stable error code taxonomy. Every error returned by an ORK either:
- comes back as an RFC 9457 ProblemDetails response with a
TIDE-ORK-*code in thecodefield and a matching URN intype, or - is wrapped in a legacy
--FAILED--envelope when the consumer is an older Tide component that cannot parse ProblemDetails
This page documents the format, the full code listing, the wire shapes, and how to add a new code without breaking cross-tier consumers.
Code format
TIDE-<PROJECT>-<CATEGORY>-<NAME>
<PROJECT>— alwaysORKfor codes emitted by an ORK node<CATEGORY>— a short uppercase category (VOUCHER,WALLET,AUTH,SIG,CRYPTO,HTTP,INTERNAL,LEGACY)<NAME>— UPPER_SNAKE_CASE describing the specific condition
Examples:
TIDE-ORK-VOUCHER-VERIFY_FAILEDTIDE-ORK-AUTH-USER_NOT_FOUNDTIDE-ORK-CRYPTO-NULL_INPUTTIDE-ORK-INTERNAL-UNEXPECTED
These strings are a stable contract. Other Tide repos (tide-js, idp-extensions, midgard) compare against these exact values to drive UI flows and downstream error reporting. Renaming a code requires coordinating across every consumer — treat them like a public API surface.
The constants live in Ork.Errors.TideErrorCodes in the ork repo and are the canonical source of truth.
Wire format — RFC 9457 ProblemDetails
When an ORK returns an error to a properly-modern caller (tide-js R3+, idp-extensions, anything emitting Accept: application/problem+json), the response body follows RFC 9457:
{"type": "urn:tide:ork:VOUCHER-VERIFY_FAILED","title": "Voucher verification failed","status": 400,"detail": "Voucher signature did not validate against the realm VRK","code": "TIDE-ORK-VOUCHER-VERIFY_FAILED","instance": "/Authentication/Voucher","traceId": "00-<32-hex>-<16-hex>-01"}
Fields:
| Field | Type | Notes |
|---|---|---|
type | URI | A URN of the form urn:tide:ork:<CATEGORY>-<NAME>. Stable; can be deep-linked from documentation |
title | string | Short human-readable summary. Safe to render in a UI |
status | integer | HTTP status code, typically 4xx for client errors and 5xx for server-side failures |
detail | string | Longer human-readable explanation. May reference specifics of the failure but must never contain user-identifying or cryptographic material |
code | string | The full TIDE-ORK-* code. The primary key consumers should switch on |
instance | string | Request path / context (often the route that produced the error) |
traceId | string | W3C traceparent value, present when the ORK is in a traced flow |
Content-Type is application/problem+json for RFC 9457 responses.
When writing a consumer, switch on code, not on status or title — status and title may evolve; code is the stable contract.
Legacy --FAILED-- envelope
For backward compatibility with older Tide nodes that cannot parse ProblemDetails, an ORK's outbound client (in Ork.Shared.Clients.ClientBase) recognises and surfaces the legacy --FAILED--[trace=...] envelope shape returned by older peers.
When ClientBase receives a legacy envelope from a peer, it:
- Logs a warning at WARN level identifying the response as legacy
- Constructs a ProblemDetails-shape result locally using the special code
TIDE-ORK-LEGACY-FAILED_ENVELOPE - Surfaces that to the caller, so callers always see a uniform shape
This means a caller that switches on code will see TIDE-ORK-LEGACY-FAILED_ENVELOPE for any legacy peer's failure response, regardless of what the peer would otherwise have wanted to report. Treat this code as "downstream node returned legacy failure envelope" — the actual cause is in the WARN-level log message body rather than the structured response.
When the entire fleet has rolled past the legacy version, the legacy-envelope code path in ClientBase can be deleted along with this section of the docs.
Code reference
Every code below is defined as a public const string in Ork.Errors.TideErrorCodes (in the ork repo). They are listed here grouped by category in the same order as they appear in the source — that order is the canonical reading order for adding new codes too.
Voucher / payment
| Code | When emitted |
|---|---|
TIDE-ORK-VOUCHER-VERIFY_FAILED | Voucher signature did not validate against the realm VRK |
TIDE-ORK-VOUCHER-PAYMENT_REJECTED | Payer-side payment check failed (insufficient funds, expired subscription, etc.) |
TIDE-ORK-VOUCHER-VRK_INVALID | VRK referenced by the voucher could not be resolved or has been revoked |
TIDE-ORK-VOUCHER-ACTION_NOT_ALLOWED | The voucher action is not permitted for this subscription tier |
TIDE-ORK-VOUCHER-ACTION_UNKNOWN | The voucher action is not recognised in the closed action allow-list |
TIDE-ORK-VOUCHER-SUBSCRIPTION_NOT_FOUND | No active subscription was found for the request's customer / realm |
TIDE-ORK-VOUCHER-SUBSCRIPTION_EXCEEDED_CONCURRENT | Subscription's concurrent-action limit was exceeded |
TIDE-ORK-VOUCHER-VENDOR_CREATION_NOT_ALLOWED | Vendor creation is not permitted on this subscription |
TIDE-ORK-VOUCHER-VENDOR_ALREADY_CREATED | A vendor with this identity already exists for this customer |
Wallet lifecycle
| Code | When emitted |
|---|---|
TIDE-ORK-WALLET-PENDING_ALREADY_EXISTS | A pending wallet for this UID already exists; the previous request did not complete or was abandoned |
Authentication / authorization
| Code | When emitted |
|---|---|
TIDE-ORK-AUTH-NODE_NOT_AUTHENTICATOR | The receiving ORK is not the configured authenticator for this UID and cannot proceed with the request |
TIDE-ORK-AUTH-USER_NOT_FOUND | UID does not exist on this ORK's local authentication database |
TIDE-ORK-AUTH-INVALID_AUTH_METHOD | The requested authentication method is not configured on this node |
Signing
| Code | When emitted |
|---|---|
TIDE-ORK-SIG-VERIFY_FAILED | Cryptographic signature verification failed at a checkpoint in the signing protocol |
Cryptography
| Code | When emitted |
|---|---|
TIDE-ORK-CRYPTO-NULL_INPUT | A cryptographic primitive was invoked with a null required input (caller bug; should never occur at runtime) |
HTTP / middleware
| Code | When emitted |
|---|---|
TIDE-ORK-HTTP-DECRYPTED_MISSING | Request middleware expected a decrypted payload to be available downstream but none was present |
Internal / catch-all
| Code | When emitted |
|---|---|
TIDE-ORK-INTERNAL-UNEXPECTED | Catch-all for any uncaught exception path. Should never appear in normal operation — its presence indicates an unhandled code path that needs investigation |
Legacy compatibility
| Code | When emitted |
|---|---|
TIDE-ORK-LEGACY-FAILED_ENVELOPE | Synthesised by Ork.Shared.Clients.ClientBase when a downstream peer returns the pre-RFC9457 --FAILED--[trace=...] envelope. See Legacy --FAILED-- envelope for context |
Trace propagation
Every ORK error response includes a traceId matching the W3C traceparent format. ORK adopts the inbound traceparent when called from a traced upstream (Phase 3 of the error-logging initiative), and propagates the same trace context on outbound calls via IHttpClientFactory + TidePropagationHandler.
In practice this means:
- A single user-driven flow that crosses TideCloak → ORK → master → payer will share a
traceIdacross every error or success response - Searching server logs for that
traceIdreturns every span the flow touched - When debugging a multi-tier failure, start by extracting
traceIdfrom the failing user's response, then grep across all relevant ORK and TideCloak logs
If a request arrives without a traceparent, the ORK generates one and uses it for outbound propagation. Either way the client always sees a traceId in error responses.
Adding a new error code
Before adding a code, check that an existing code does not already cover the case. Code proliferation makes the consumer side harder to maintain.
When a new code is genuinely needed:
- Pick the category. If none of the existing categories fit, add a new category constant (still uppercase, still single-segment).
- Add the constant to
Ork.Errors.TideErrorCodesin the canonical order (group with similar codes). - Wire it at the emit site. Use the
TideOperationExceptionmechanism — barethrow new Exceptionis banned byBannedApiAnalyzersso the build will fail if you skip this step. - Document it here. Add a row to the appropriate category table in this page describing when the code is emitted.
- Notify consumers. Open a tracking ticket for tide-js and any other repo that switches on
TIDE-ORK-*codes — they may need to add a new branch in their error handler. - Do not remove codes. Even if a code becomes unused on the emit side, removing it is a wire-breaking change for any consumer with stored data referencing it. Mark it deprecated in this doc instead.
Related references
- Metrics reference: ORK Metrics
- Forseti concept: Programmable Policy
- RFC 9457 ProblemDetails: rfc-editor.org/rfc/rfc9457.html
- W3C Trace Context (
traceparent): w3.org/TR/trace-context