Error Codes
Every code the framework answers a request with, as code of the application/problem+json body and in a command's result, generated from FrameworkErrors. A domain rejection's code is the domain's own; it is answered with 422 unless the host sets another status for it (wow.http.errors.[<code>].status). With If-Match, wow.aggregate.version-mismatch is answered with 412. Every problem carries what a retry may do as its retry member: none, a retry fails alike; same-request, send it again with the same Wow-Request-Id; new-request, send it again as it is; with Retry-After whenever a retry may get past it. A domain's code is none.
Framework codes
| Code | Status | Retry | Title | Meaning |
|---|---|---|---|---|
wow.auth.unauthenticated | 401 | none | Unauthenticated | The request carries no valid credentials. |
wow.auth.forbidden | 403 | none | Forbidden | The caller may not do what the request asks: send this command, call this route, or act or read across scopes. |
wow.aggregate.forbidden | 403 | none | Aggregate change forbidden | The caller may read the aggregate but may not change it, or the command would create one outside the caller's reach. |
wow.request.malformed | 400 | none | Malformed request | A request header or parameter does not parse, or names what Wow does not take. |
wow.command.malformed | 400 | none | Malformed command | The command body cannot be read as the command type. |
wow.command.invalid | 400 | none | Invalid command | The command failed validation; the problem lists the violations. |
wow.wait.invalid | 400 | none | Invalid wait | The wait is not a chain the runtime can follow; the command was not run. |
wow.command.unhandled | 400 | none | Command not handled | The aggregate does not handle this command. |
wow.aggregate.not-found | 404 | none | Aggregate not found | The aggregate does not exist, or is outside the caller's reach. |
wow.aggregate.exists | 409 | none | Aggregate exists | The aggregate already exists. |
wow.aggregate.version-mismatch | 409 | none | Version mismatch | The aggregate is not at the expected version (412 when the request carried If-Match). |
wow.command.request-id-reused | 409 | none | Request id reused | The request id was used by another command. |
wow.command.contended | 409 | same-request | Command contended | Concurrent writers kept winning the version; retrying with the same request id is safe. |
wow.aggregate.deleted | 410 | none | Aggregate deleted | The aggregate is deleted; only RestoreAggregate applies. |
wow.command.busy | 429 | same-request | Command busy | The command was not taken: its aggregate has too many commands waiting, or the node too many in flight; retry later. |
wow.command.unknown | 503 | same-request | Command outcome unknown | Whether the command committed is unknown; retrying with the same request id is safe. |
wow.command.failed | 500 | none | Command failed | The command's handling failed with an unexpected error; it committed nothing, and a retry fails alike. |
wow.command.refused | 409 | none | Command refused | The aggregate's current state refuses the command (a check of its decide function); the message says why. |
wow.command.undeclared-event | 500 | none | Undeclared event | The command's handling produced an event its decide function or after hooks do not declare: a bug in the model, which the message names; it committed nothing. |
wow.node.closing | 503 | same-request | Node closing | The node is shutting down; retry on another node. |
wow.node.standby | 503 | same-request | Node on standby | The node is on standby until the cut-over: it serves reads only. |
wow.storage.unavailable | 503 | same-request | Storage unavailable | A store could not be reached or did not answer in time; retry later, a command with the same request id. |
wow.schedule.not-due | 503 | same-request | Schedule not due | A scheduled command arrived too long before its due time on this node's clock; it is sent again later. |
wow.schedule.job-invalid | 400 | none | Invalid schedule job | The job command does not fit its job or instance: an unknown job, another scope, or an instance not enabled. |
wow.ledger.stale | 409 | none | Stale ledger action | The action names a parking the entry no longer is: the aggregate was resolved and parked again since; read the entry again before acting on it. |
wow.subscription.parked | 500 | none | Subscription parked | A subscription on the wait chain parked the aggregate; the wait cannot be reached until the aggregate is retried. |
wow.wait.timeout | 504 | same-request | Wait timed out | The wait ran out of time; the command may have committed. The problem carries the last stage reached. |
wow.route.malformed | 400 | none | Malformed route request | A service route's parameter or body cannot be read as its type; the violation names the parameter. |
wow.query.malformed | 400 | none | Malformed query | The query body cannot be read as a query. |
wow.query.invalid | 400 | none | Invalid query | The query failed admission; the problem lists the violations, each with its code (unknown-field, ...). |
wow.query.failed | 500 | none | Query failed | The query backend failed to run the query. |
wow.query.not-found | 404 | none | No matching record | A single query matched no record: a query result, not a statement that an aggregate does not exist. |
wow.query.dataset-not-found | 404 | none | Dataset not found | No dataset of that name is served to the caller. |
wow.query.too-many-groups | 400 | none | Too many groups | An aggregation that names no sort has more groups than its limit; add a sort for a top-N, or raise limit. |
wow.query.timeout | 504 | none | Query timed out | The query ran longer than its budget allows; narrow it rather than run it again. |
wow.query.min-version-not-reached | 409 | new-request | Version not reached | The state read asked for a version the aggregate has not reached within the wait; the problem carries its current version: retry later. |
wow.query.busy | 429 | new-request | Query busy | The query was not run: its store has as many queries running as it allows; retry later. |
wow.query.dataset-unavailable | 409 | none | Dataset unavailable | The dataset is served but cannot be queried now, for the reason the problem names (it needs revision). |
wow.call.command-forbidden | 403 | none | Call forbidden | The calling service may not call this command: its wow.callers.<service>.commands do not list it. |
wow.peer.unavailable | 503 | new-request | Peer unavailable | A client reached no node of the peer, or lost the connection before a query's answer; nothing was changed, so the request may be sent again. |
Query request codes
A rejected query request (wow.query.malformed or wow.query.invalid) lists what it rejects, each with one of these codes and the part of the request it names, generated from QueryErrorCodes. Codes are added, never renamed or reused.
| Code | Group |
|---|---|
invalid-json | Reading and decoding the request body. |
body-not-object | Reading and decoding the request body. |
empty-body | Reading and decoding the request body. |
unknown-property | Reading and decoding the request body. |
unknown-type | Reading and decoding the request body. |
unknown-value | Reading and decoding the request body. |
invalid-value | Reading and decoding the request body. |
invalid-request | Reading and decoding the request body. |
cursor-sort-duplicate | Reading and decoding the request body. |
cursor-sort-too-many | Reading and decoding the request body. |
invalid-cursor | Reading and decoding the request body. |
stream-not-resumable | Reading and decoding the request body. |
size-out-of-range | The entry budget and gates. |
filter-too-large | The entry budget and gates. |
expensive-operator-disabled | The entry budget and gates. |
count-requires-filter | The entry budget and gates. |
residual-groups-exceeded | The entry budget and gates. |
too-many-groups | The entry budget and gates. |
explicit-entry-required | The entry budget and gates. |
replay-too-long | A state point read. |
unknown-field | Admission against the query model. |
unsupported-capability | Admission against the query model. |
element-scope-required | Admission against the query model. |
value-mismatch | Admission against the query model. |
not-collection | Admission against the query model. |
not-single-string | Admission against the query model. |
model-search-unsupported | Admission against the query model. |
cursor-not-allowed | Admission against the query model. |
protected-aggregation | Admission against the query model. |
protected-comparison | Admission against the query model. |
missing-key-requires-string | Admission against the query model. |
any-requires-single-value | Admission against the query model. |
incomplete-projection | Admission against the query model. |
metric-filter-search | Admission against the query model. |
metric-filter-element-match | Admission against the query model. |
metric-filter-array-field | Admission against the query model. |
not-projectable | Admission against the query model. |
event-projection-type-required | Admission against the query model. |
temporal-representation-required | Admission against the query model. |
temporal-configuration-conflict | Admission against the query model. |
parallel-array-sort | Admission against the query model. |
array-equality | Admission against the query model. |
first-last-requires-single-value | Admission against the query model. |
first-last-requires-order-by | Admission against the query model. |
temporal-aggregation-unsupported | Admission against the query model. |
sort-too-many | Admission against the query model. |
sort-field-duplicate | Admission against the query model. |
identity-undefined | Admission against the query model. |
storage-unsupported | Admission against the query model. |
previous-unshiftable | Admission against the query model. |