Error Reference
This page is the canonical reference for every error code defined in OIP v0.5. It consolidates the 36 codes into a single matrix, defines the five handling actions, specifies how failures propagate through the three-phase cross-chain coordination, and distinguishes states that look similar at the surface but require different recovery paths. Conformant implementations MUST emit and process all 36 codes listed here.
Sister specification pages introduce the conditions that produce each code in context. Validation defines the eight validation criteria and the sub-checks that fire most of these errors, State Management covers the state-transition family, Cross-chain Protocol covers the divergence and reconciliation flow, and Fault Tolerance covers retry policies, deduplication, and the Dead Letter Queue. This page is the lookup table and the recovery-semantics reference; those pages explain the surrounding logic.
Handling Actions
OIP v0.5 defines five handling actions. Every error code maps to exactly one of these, and the mapping is part of the protocol contract: a sender can rely on receiving a deterministic response class for any given code. The five actions partition the failure space into distinct recovery paths.
Figure 1: Handling Actions
The remaining codes fall into silent or automatic categories: DEDUPLICATION_DETECTED is silently ignored as part of idempotency, RECONCILIATION_REQUIRED auto-triggers the reconciliation flow, and MAX_RETRIES_EXCEEDED moves the message into the Dead Letter Queue. ESCALATE is not directly mapped from a single error code; it is the dynamic response invoked by validation logic when an incoming STATE_SYNC resolves to a regulatory-action category, as defined in Validation.
REJECT vs FAILED ACK Distinction
When a node refuses a message, it returns an ACK whose ackType distinguishes the failure mode. The choice carries semantic meaning: REJECTED means the message was structurally or contextually invalid and processing never began, while FAILED means the message was accepted into the pipeline but failed during state evaluation.
This distinction matters for senders building retry logic. A REJECTED response indicates the sender constructed an invalid message and should fix the message itself before resending; a FAILED response indicates the receiver-side state changed (or was inconsistent) and the sender may retry after refreshing local state. Confusing the two leads to retry storms or, conversely, to silently dropped recoverable failures.
interface ErrorAckPayload {
acknowledgedMessageId: string;
ackType: "FAILED" | "REJECTED";
resultCode: string; // one of the 36 error codes
errorDetails: ErrorDetails;
}
interface ErrorDetails {
errorCode: string;
errorMessage: string; // human-readable description
retryable: boolean;
suggestedAction?: "RETRY" | "ROLLBACK" | "ESCALATE" | "ABORT";
contextData?: object; // optional debugging data
}
The retryable flag is the operational shortcut: senders that want simple logic can branch on this single boolean rather than parsing the error code itself. suggestedAction is advisory; final retry policy is governed by the message type’s policy in Fault Tolerance.
The figure below summarizes the decision flow a sender follows on receiving an ACK. Implementations may collapse this into a switch on retryable alone, but the explicit form helps understand why each branch exists.
ackType = REJECTED
ackType = FAILED
ackType = FAILED
Figure 2: ACK Handling Decision
Error Code Categories
OIP v0.5 organizes the 36 error codes into seven categories by prefix. The category prefix is a contractual element of the protocol: clients receiving an unknown code SHOULD fall back to category-level handling rather than rejecting the entire ACK. This is the foundation of forward compatibility (see Extension Policy).
Figure 3: Category Distribution
Authority
Errors raised when a message claims regulatory authority that the receiver cannot verify. All four codes REJECT with non-retryable semantics: the sender’s authority claim itself is wrong, and resending the same claim cannot succeed. These checks fire during validation criterion (3) authority verification, before any state mutation is attempted.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
AUTHORITY_NOT_REGISTERED | Sender’s authorityId not found in Authority Registry | REJECT | REJECTED |
JURISDICTION_MISMATCH | Authority’s jurisdiction does not match the asset’s jurisdiction | REJECT | REJECTED |
ACTION_NOT_PERMITTED | Authority not permitted to perform the requested action | REJECT | REJECTED |
CRITICAL_PRIORITY_NOT_AUTHORIZED | Sender lacks the role required to assign Priority.CRITICAL | REJECT | REJECTED |
State Transition
Errors raised when a state transition violates the matrix in State Management or when a postcondition fails after partial execution. The Escalation Chain errors (FREEZE_REQUIRED_BEFORE_SEIZE, SEIZE_REQUIRED_BEFORE_CONFISCATE) enforce the legally required ordering of regulatory actions and are non-retryable until the sender first applies the missing predecessor action.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
STATE_HASH_MISMATCH | currentStateHash does not match the actual state hash on the receiver | REJECT | FAILED |
FREEZE_REQUIRED_BEFORE_SEIZE | Asset is not in RESTRICTED state when SEIZE arrives | REJECT | REJECTED |
SEIZE_REQUIRED_BEFORE_CONFISCATE | Asset is not in SEIZED state when CONFISCATE arrives | REJECT | REJECTED |
INVALID_STATE_TRANSITION | Transition not defined in the State Transition Matrix | REJECT | REJECTED |
POSTCONDITION_VIOLATION_SINGLE | Single-chain postcondition fails after Group 3 evaluation | ROLLBACK | FAILED |
POSTCONDITION_VIOLATION_MULTI | Multi-chain postcondition fails; ALL_OR_NOTHING rollback triggered | ROLLBACK | FAILED |
STATE_HASH_MISMATCH uses FAILED rather than REJECTED because the message itself was structurally valid; only the receiver-side state diverged. Senders should refresh local state from the receiver and resend with the updated hash. The two POSTCONDITION_VIOLATION_* codes differ in scope: see the dedicated POSTCONDITION_VIOLATION Single vs Multi section below for the rollback-sequence comparison.
Legal Basis
Errors raised when the legal documentation accompanying a regulatory action is structurally invalid, expired, or premature. APPEAL_PERIOD_NOT_EXPIRED guards CONFISCATE specifically: a confiscation cannot proceed before the asset’s appeal window has closed.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
INVALID_LEGAL_DOCUMENT_STRUCTURE | LegalReference structure missing required fields or malformed | REJECT | REJECTED |
EVIDENCE_HASH_INVALID | evidence.documentHash verification failed | REJECT | REJECTED |
LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID | issuedAt > now or validUntil < now | REJECT | REJECTED |
APPEAL_PERIOD_NOT_EXPIRED | CONFISCATE submitted with appealDeadlinePassed != true | REJECT | REJECTED |
APPEAL_PERIOD_NOT_EXPIRED and LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID are time-variant errors: the same message may succeed at a different point in time. See Time-Variant Errors and Retry Semantics for the retry timing model.
Cross-chain
Errors that arise when the system detects inconsistency across chains or when a target chain cannot fulfill an atomicity requirement. Most codes in this category surface during the COMMIT phase of three-phase coordination; see Phase-Level Failure Semantics for the exact mapping. The DIVERGE family (CROSS_CHAIN_STATE_CONFLICT, DIVERGED_STATE_DETECTED) is qualitatively distinct from REJECT: rather than refusing a single message, it pauses the entire asset until reconciliation completes.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
CROSS_CHAIN_STATE_CONFLICT | State on this chain conflicts with state on another chain | DIVERGE | FAILED |
ATOMIC_COMMIT_NOT_SUPPORTED | Target chain capabilities do not support atomic commit | REJECT | REJECTED |
DIVERGED_STATE_DETECTED | New message arrives while reconciliation is in progress | DIVERGE | FAILED |
RECONCILIATION_REQUIRED | Auto-trigger signal for reconciliation; not sender-facing | auto-trigger | (none) |
ROLLBACK_INCOMPLETE_REJECT | New transaction submitted while in ROLLBACK_INCOMPLETE state, awaiting governance resolution | REJECT | REJECTED |
RECONCILIATION_REQUIRED is the only code in the entire reference that is not sender-facing: it is an internal signal a node emits to itself or to peer nodes to trigger the reconciliation flow. Senders never receive this code in an ACK. DIVERGED state and ROLLBACK_INCOMPLETE state look superficially similar but represent different recovery paths; see DIVERGED vs ROLLBACK_INCOMPLETE for the comparison.
Address
Errors raised during address resolution. The OIP OIPAddress format combines ERC-3770 short names with CAIP-2 chain identifiers; any failure in this resolution chain produces one of these four codes. Address-resolution checks run before authority verification because an unresolvable address makes downstream authority lookup impossible.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
INVALID_ADDRESS_FORMAT | Address violates ERC-3770 or OIPAddress format | REJECT | REJECTED |
UNKNOWN_CHAIN_SHORT_NAME | Short name not found in Short Name Registry | REJECT | REJECTED |
INVALID_ADDRESS_CHECKSUM | Mixed-case address fails EIP-55 checksum verification | REJECT | REJECTED |
CHAIN_NOT_SUPPORTED | Chain not registered in ChainRegistry or marked inactive | REJECT | REJECTED |
INVALID_ADDRESS_CHECKSUM applies only to mixed-case addresses; lowercase or fully uppercase addresses bypass checksum validation per EIP-55. Senders should always emit mixed-case addresses to benefit from the typo-detection guarantee.
Delivery
Errors related to message lifecycle and transport. This category contains the only RETRY code (DELIVERY_TIMEOUT) and the only DLQ code (MAX_RETRIES_EXCEEDED) in the entire reference. The full delivery model, including retry policies per message type and the DLQ recovery protocol, lives in Fault Tolerance.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
MESSAGE_TTL_EXPIRED | header.timestamp + routing.ttl < now at receiver | REJECT | REJECTED |
DELIVERY_TIMEOUT | Phase timeout exceeded during delivery | RETRY | (none) |
MAX_RETRIES_EXCEEDED | Retry policy maxRetries reached | DLQ | FAILED |
DEDUPLICATION_DETECTED | messageId already in deduplication cache | silently ignored | (none) |
UNSUPPORTED_VERSION | Receiver does not support header.version | REJECT | REJECTED |
DEDUPLICATION_DETECTED is silently ignored as part of OIP's idempotency contract: detecting a duplicate is a normal operational event, not a failure, and the sender already received the original ACK. Generating a new ACK for the duplicate would itself violate idempotency.
Message Integrity
The largest category. These eight codes cover every aspect of cryptographic verification, attestation validation, and replay protection. Three of these codes apply only to messages originating from Canton via a Canton Driver; see CANTON-Specific Codes for the dedicated subset. Two codes (INVALID_SIGNATURE, INVALID_THRESHOLD_SIGNATURE) are flagged for slashing review when the failure pattern suggests malicious behavior; see Slashing-Eligible Codes.
| Code | Trigger | Action | ACK Type |
|---|---|---|---|
INVALID_HEADER_FORMAT | OIPMessageHeader structure violation | REJECT | REJECTED |
INVALID_SIGNATURE | SINGLE signature verification failed | REJECT | REJECTED |
INVALID_THRESHOLD_SIGNATURE | BLS aggregated signature failed or quorum not met | REJECT | REJECTED |
INVALID_SOURCE_AUTHENTICATION | Source chain proof missing or invalid | REJECT | REJECTED |
INVALID_DRIVER_ATTESTATION | driverSignature verification failed or structurally malformed | REJECT | REJECTED |
DRIVER_NOT_REGISTERED | driverId not found in Driver Registry | REJECT | REJECTED |
PARTY_OCID_MAPPING_INVALID | partyMapping.mappingProof verification failed | REJECT | REJECTED |
ATTESTATION_REPLAY_DETECTED | cantonContext.transactionId already processed | REJECT | REJECTED |
ATTESTATION_REPLAY_DETECTED closes a specific replay vector that DEDUPLICATION_DETECTED alone cannot catch: the same Canton transaction wrapped in two different OIP messages with different messageId values would pass the messageId dedup check but fail this one.
Phase-Level Failure Semantics
Cross-chain messages travel through a three-phase staged coordination: PREPARE, COMMIT, FINALIZE, defined in Cross-chain Protocol. Each phase has its own failure semantics: which errors can fire, what side effects roll back, and what the lock holds. This section is the recovery-semantics reference for cross-chain operations.
STATE_HASH_MISMATCH
INVALID_STATE_TRANSITION
AUTHORITY_NOT_REGISTERED
POSTCONDITION_VIOLATION_*
DIVERGED_STATE_DETECTED
ROLLBACK_INCOMPLETE_REJECT
MAX_RETRIES_EXCEEDED
Figure 4: Phase-Level Failure Semantics
PREPARE Failure
The preemptive lock is acquired at the start of PREPARE. If validation fails inside PREPARE, the abort path releases the lock immediately. During a retry attempt, the lock is held to prevent racing transactions from acquiring it; if all retries fail, the lock is held until its TTL expires, at which point it is released automatically. This behavior aligns with the lock-timeout safety property of the Preemptive Lock Correctness verification.
COMMIT Failure
COMMIT failures are the most consequential because state has already changed on at least one chain when the failure is detected. Two distinct failure modes arise: cross-chain state conflict (some chains saw the change, others did not, or one rejected it) and intentional rollback in progress. The protocol distinguishes these by transitioning to either DIVERGED or ROLLBACK_INCOMPLETE; see the next section for the comparison.
FINALIZE Failure
FINALIZE is the lock-release signal. Failures here are treated conservatively: the state change is NOT rolled back. The reasoning is that FINALIZE failure is a "confirmation failure," not a "state-change failure." Rolling back a successfully committed state because the confirmation message was lost would create more risk than it solves: a transient network glitch could invalidate legitimate transactions. Instead, chains that did not receive FINALIZE keep their lock held until TTL expires, at which point it is released automatically.
DIVERGED vs ROLLBACK_INCOMPLETE
These two states look similar at the surface but are produced by different causes and have different recovery paths. Confusing them in operations leads to applying the wrong recovery procedure. The protocol intentionally separates them so that automatic systems can route based on the state alone, without having to inspect the underlying error code.
CROSS_CHAIN_STATE_CONFLICT, DIVERGED_STATE_DETECTEDmaxRollbackWindow; partial rollback state remains.ROLLBACK_INCOMPLETE_REJECT (rejects new traffic)Figure 5: DIVERGED vs ROLLBACK_INCOMPLETE
The cleanest way to think about the difference: DIVERGED is "we don't know which chain is right yet", while ROLLBACK_INCOMPLETE is "we know what should happen but haven't finished doing it". Reconciliation discovers the truth; governance enforces it.
POSTCONDITION_VIOLATION Single vs Multi
POSTCONDITION_VIOLATION_SINGLE and POSTCONDITION_VIOLATION_MULTI share the same prefix and the same handling action (ROLLBACK), but their operational consequences differ by an order of magnitude. The single-chain variant triggers a local rollback on one chain; the multi-chain variant triggers an ALL_OR_NOTHING rollback sequence across every chain involved in the transaction.
| Aspect | POSTCONDITION_VIOLATION_SINGLE | POSTCONDITION_VIOLATION_MULTI |
|---|---|---|
| Scope | One chain only | All chains in the transaction sequence |
| Rollback trigger | Group 2 single-chain rollback | ALL_OR_NOTHING sequence rollback |
| Sender retryability | retryable: true (resend the same transaction) | retryable: false (start a fresh sequence) |
| Lock release | Local lock only | All locks across the sequence |
| Operational cost | Low (single-chain rollback) | High (multi-chain coordinated rollback) |
The retryable: false on the multi-chain variant is not a permanent rejection. It signals that the specific in-flight sequence has been fully unwound; senders construct a new sequence with a new messageId rather than resending the failed one. This avoids races between the rollback completion and an immediate retry.
Time-Variant Errors and Retry Semantics
Three error codes have outcomes that change with the passage of time. The same message that fails now may succeed at a later point, without any change to the message itself. Senders must understand the timing model for each, because retry-too-early just produces another failure, and retry-too-late may run into TTL expiration.
| Code | Becomes valid when | Retry guidance |
|---|---|---|
MESSAGE_TTL_EXPIRED | Never (message is dead) | Construct a new message with a fresh messageId and timestamp. The original cannot be revived. |
LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID | If issuedAt > now: at issuedAt. If validUntil < now: never; obtain new legal documentation. | For not-yet-valid: schedule retry at issuedAt. For expired: replace LegalReference entirely. |
APPEAL_PERIOD_NOT_EXPIRED | At appealDeadline | Schedule retry at appealDeadline with appealDeadlinePassed: true. |
Implementations SHOULD attach the relevant timestamp (issuedAt, appealDeadline) to errorDetails.contextData so that automated retry schedulers can compute the correct retry time without consulting external sources. The protocol does not require this, but the operational benefit is substantial.
Slashing-Eligible Codes
Two error codes mark failures that may indicate malicious behavior rather than transient corruption. When the failure pattern (frequency, source, correlation across messages) suggests deliberate misbehavior, these codes are flagged for slashing review at the consensus layer. The slashing decision itself is governed by the consensus layer, not by the protocol message; the error code is a signal, not a slashing trigger.
| Code | Why slashing-eligible | What triggers review |
|---|---|---|
INVALID_SIGNATURE | SINGLE signature failure may mean the sender's key was used to sign an invalid message. Pattern of repeated failures from the same node points at compromise or malice. | Repeated failures from a single node within a short window. The consensus layer aggregates these signals. |
INVALID_THRESHOLD_SIGNATURE | BLS threshold signature failure may mean a coalition of nodes failed to honor their attestation duty. Pattern of failures suggests coordinated misbehavior. | Failure rate above the BFT threshold from a specific signer set, especially if the failure correlates with controversial messages. |
Other Message Integrity codes (INVALID_HEADER_FORMAT, INVALID_SOURCE_AUTHENTICATION, etc.) do not directly imply malicious intent: they are typically caused by software bugs, version skew, or relayer errors. A node receiving these codes simply rejects the message; there is no slashing review path.
CANTON-Specific Codes
Four codes apply only to messages originating from Canton via a Canton Driver. EVM-originated messages never produce these codes. The codes form a contiguous subset of the Message Integrity category and reflect the additional verification surface introduced by the Canton attestation model.
| Code | What it verifies |
|---|---|
INVALID_DRIVER_ATTESTATION | The Canton Driver's signature over the bridged message is valid and the attestation structure is well-formed. |
DRIVER_NOT_REGISTERED | The driverId appears in the Driver Registry. Unknown drivers are rejected outright. |
PARTY_OCID_MAPPING_INVALID | The proof binding a Canton Party to an OCID is valid. This protects against impersonation across the on-chain/off-chain boundary. |
ATTESTATION_REPLAY_DETECTED | The underlying Canton transaction has not already been processed under a different OIP messageId. |
Implementations that do not integrate with Canton can omit the validation logic for these codes (no Canton-originated messages will ever reach them), but they MUST still emit these codes correctly if they observe a malformed or replayed Canton attestation. Forward compatibility requires the codes to be present in every conformant implementation's vocabulary, even when the implementation never produces them in practice.
Complete Error Code Matrix
The full matrix of all 36 codes in a single table, sorted by category and code number. This is the canonical lookup table for implementations. The Retryable column reflects the retryable flag in ErrorDetails; conditional values are explained inline.
| # | Category | Code | Action | ACK | Retryable |
|---|---|---|---|---|---|
| 1 | Authority | AUTHORITY_NOT_REGISTERED | REJECT | REJECTED | false |
| 2 | Authority | JURISDICTION_MISMATCH | REJECT | REJECTED | false |
| 3 | Authority | ACTION_NOT_PERMITTED | REJECT | REJECTED | false |
| 4 | Authority | CRITICAL_PRIORITY_NOT_AUTHORIZED | REJECT | REJECTED | false |
| 5 | State Transition | STATE_HASH_MISMATCH | REJECT | FAILED | true (after refresh) |
| 6 | State Transition | FREEZE_REQUIRED_BEFORE_SEIZE | REJECT | REJECTED | false |
| 7 | State Transition | SEIZE_REQUIRED_BEFORE_CONFISCATE | REJECT | REJECTED | false |
| 8 | State Transition | INVALID_STATE_TRANSITION | REJECT | REJECTED | false |
| 9 | State Transition | POSTCONDITION_VIOLATION_SINGLE | ROLLBACK | FAILED | true |
| 10 | State Transition | POSTCONDITION_VIOLATION_MULTI | ROLLBACK | FAILED | false |
| 11 | Legal Basis | INVALID_LEGAL_DOCUMENT_STRUCTURE | REJECT | REJECTED | false |
| 12 | Legal Basis | EVIDENCE_HASH_INVALID | REJECT | REJECTED | false |
| 13 | Legal Basis | LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID | REJECT | REJECTED | false |
| 14 | Legal Basis | APPEAL_PERIOD_NOT_EXPIRED | REJECT | REJECTED | true (after window) |
| 15 | Cross-chain | CROSS_CHAIN_STATE_CONFLICT | DIVERGE | FAILED | false |
| 16 | Cross-chain | ATOMIC_COMMIT_NOT_SUPPORTED | REJECT | REJECTED | false |
| 17 | Cross-chain | DIVERGED_STATE_DETECTED | DIVERGE | FAILED | false |
| 18 | Cross-chain | RECONCILIATION_REQUIRED | auto | (none) | N/A |
| 19 | Cross-chain | ROLLBACK_INCOMPLETE_REJECT | REJECT | REJECTED | false |
| 20 | Address | INVALID_ADDRESS_FORMAT | REJECT | REJECTED | false |
| 21 | Address | UNKNOWN_CHAIN_SHORT_NAME | REJECT | REJECTED | false |
| 22 | Address | INVALID_ADDRESS_CHECKSUM | REJECT | REJECTED | false |
| 23 | Address | CHAIN_NOT_SUPPORTED | REJECT | REJECTED | false |
| 24 | Delivery | MESSAGE_TTL_EXPIRED | REJECT | REJECTED | true (new message) |
| 25 | Delivery | DELIVERY_TIMEOUT | RETRY | (none) | true (automatic) |
| 26 | Delivery | MAX_RETRIES_EXCEEDED | DLQ | FAILED | false |
| 27 | Delivery | DEDUPLICATION_DETECTED | silent | (none) | N/A |
| 28 | Delivery | UNSUPPORTED_VERSION | REJECT | REJECTED | false |
| 29 | Message Integrity | INVALID_HEADER_FORMAT | REJECT | REJECTED | false |
| 30 | Message Integrity | INVALID_SIGNATURE | REJECT | REJECTED | false |
| 31 | Message Integrity | INVALID_THRESHOLD_SIGNATURE | REJECT | REJECTED | false |
| 32 | Message Integrity | INVALID_SOURCE_AUTHENTICATION | REJECT | REJECTED | false |
| 33 | Message Integrity | INVALID_DRIVER_ATTESTATION | REJECT | REJECTED | false |
| 34 | Message Integrity | DRIVER_NOT_REGISTERED | REJECT | REJECTED | false |
| 35 | Message Integrity | PARTY_OCID_MAPPING_INVALID | REJECT | REJECTED | false |
| 36 | Message Integrity | ATTESTATION_REPLAY_DETECTED | REJECT | REJECTED | false |
Validation Criteria Mapping
The eight validation criteria defined in Validation map to specific error codes. Implementations can use this table to localize a failure: knowing the failing criterion narrows the diagnostic surface to a small set of codes.
| Criterion | Related Error Codes |
|---|---|
| (1) Message integrity | INVALID_HEADER_FORMAT, INVALID_SIGNATURE, INVALID_THRESHOLD_SIGNATURE, INVALID_SOURCE_AUTHENTICATION, INVALID_DRIVER_ATTESTATION, DRIVER_NOT_REGISTERED, PARTY_OCID_MAPPING_INVALID, MESSAGE_TTL_EXPIRED, UNSUPPORTED_VERSION |
| (2) Duplicate / replay protection | DEDUPLICATION_DETECTED, ATTESTATION_REPLAY_DETECTED |
| (3) Authority verification | AUTHORITY_NOT_REGISTERED, JURISDICTION_MISMATCH, ACTION_NOT_PERMITTED, CRITICAL_PRIORITY_NOT_AUTHORIZED |
| (4) Precondition check | INVALID_STATE_TRANSITION, FREEZE_REQUIRED_BEFORE_SEIZE, SEIZE_REQUIRED_BEFORE_CONFISCATE |
| (5) State invariant | STATE_HASH_MISMATCH, INVALID_STATE_TRANSITION, POSTCONDITION_VIOLATION_SINGLE, POSTCONDITION_VIOLATION_MULTI |
| (6) Time constraint | LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID, APPEAL_PERIOD_NOT_EXPIRED |
| (7) Proof verification | EVIDENCE_HASH_INVALID, INVALID_LEGAL_DOCUMENT_STRUCTURE |
| (8) Cross-chain consistency | CROSS_CHAIN_STATE_CONFLICT, ATOMIC_COMMIT_NOT_SUPPORTED, DIVERGED_STATE_DETECTED, RECONCILIATION_REQUIRED, ROLLBACK_INCOMPLETE_REJECT |
| Delivery (separate) | DELIVERY_TIMEOUT, MAX_RETRIES_EXCEEDED |
| Address resolution (separate) | INVALID_ADDRESS_FORMAT, UNKNOWN_CHAIN_SHORT_NAME, INVALID_ADDRESS_CHECKSUM, CHAIN_NOT_SUPPORTED |
INVALID_STATE_TRANSITION appears under both criterion (4) and criterion (5) because the same code is emitted when the transition is undefined in the matrix (precondition view) and when applying it would break a state invariant (postcondition view). Implementations may attach a contextData.subCriterion hint to disambiguate, but the protocol does not require it.
Extension Policy
OIP v0.5 defines exactly 36 error codes. Future versions may add new codes under the following rules.
- Category prefix consistency: a new code MUST belong to one of the seven existing categories. Introducing a new category requires a major version increase.
- Major version change: changing the meaning of an existing code is a breaking change and triggers a major version increase.
- Minor version change: adding new codes within existing categories is non-breaking and triggers a minor version increase.
- Forward compatibility: clients receiving an unknown error code SHOULD fall back to category-level handling based on the prefix. For example, an unknown
STATE_*code should be treated as a state-transition family error, applying the closest known recovery path.
The forward-compatibility rule is the practical reason every code carries a meaningful prefix. A v0.5 client interoperating with a v0.6 implementation may encounter STATE_NEW_CONDITION_FOO; the prefix lets it route the failure into its existing state-transition handler rather than crashing or treating the message as unknown garbage. During the v0.x phase (before v1.0), even minor version changes can be incompatible; clients should not rely on forward compatibility as a substitute for version negotiation.
References
- EIP-55: Mixed-case checksum address encoding
- ERC-3770: Chain-specific addresses
- CAIP-2: Blockchain ID specification
- RFC 2119: Key words for use in RFCs to indicate requirement levels
Related Pages
- Validation: the eight validation criteria and processing pipelines that emit these codes
- State Management: state transition matrix and Escalation Chain rules
- Cross-chain Protocol: PREPARE/COMMIT/FINALIZE staged coordination and reconciliation flow
- Fault Tolerance: retry policies, deduplication, DLQ recovery protocol
- Regulatory Actions: Escalation Chain and CONFISCATE appeal window
