Every error these contracts can return, with a stable code, the condition that produces it, whether retrying can help, and what to do about it.
The catalog below is generated from packages/shared/src/error_catalog.rs and checked by tests/error-catalog/. It is not maintained by hand: to change it, change the catalog and regenerate with
cargo test -p error-catalog-tests -- --ignored regenerate
Backend mapping guidance, including how to handle a code this document does not list, is in Backend Integration.
Code is the contract. Clients switch on the number, never on the variant name. A published code is never renumbered and never reused for a different meaning; removing one is a breaking change, adding one is not.
Domain is the allocated range the code falls in:
| Range | Domain | Enum |
|---|---|---|
| 1-99 | common | ContractError |
| 100-199 | protocol-config | none yet; reserved |
| 200-299 | issuer-registry | IssuerError |
| 300-399 | proof-registry | ProofError |
The protocol-config range is allocated but empty: that contract returns common errors only. The range stays reserved so a future protocol-config error cannot collide with anything.
Status distinguishes a code that some contract path actually returns from one that is declared and reserved but produced by nothing in this release. Eight codes are currently reserved, and the distinction matters in practice: see the ambiguity note below before writing a client that waits for one of them.
Retry answers whether repeating the call can ever succeed:
| Retry | Meaning | What a client should do |
|---|---|---|
never |
Deterministic rejection | Surface it. Do not retry, on any schedule. |
after-operator-action |
Succeeds once an operator or admin changes protocol state | Queue or poll the relevant read (is_paused, is_active_address, is_schema_version_approved) rather than retrying the write blindly. |
after-caller-change |
Succeeds if the request itself changes | Fix the request. Retrying it unchanged fails identically. |
An unrecognised code is always never. A client that has not seen a code cannot know whether the call had a side effect, so replaying it is never safe.
The following codes are now properly separated (no longer overloaded):
Previously (pre-fix): Three conditions shared code 304 InvalidSchemaVersion:
- the schema version is zero;
- the protocol is paused;
- the issuer address is not active.
Currently (post-fix): Each precondition has its distinct code:
| Code | Condition | Retry | Recovery |
|---|---|---|---|
| 304 | schema version is zero | never | Use a non-zero schema version |
| 307 | protocol is paused | after-operator-action | Poll is_paused and wait for unpause |
| 308 | issuer is inactive | after-operator-action | Call is_active_address and wait for reactivation |
| 309 | schema not approved | after-operator-action | Call is_schema_version_approved and wait for approval |
This separation enables clients to distinguish between different failure modes and take appropriate recovery actions, rather than checking all three conditions blindly on receipt of 304.
A Soroban contract error is a type and a number. It carries no message, no payload, and no record content, so a failing call cannot leak what it touched. Three properties follow, each asserted in the test crate:
- Authorization failures are undifferentiated. Every authorization rejection is the same outcome regardless of which address would have been accepted, and none reveals whether a record exists.
- Client messages are fixed strings. No entry contains an interpolation marker, so a client is never invited to splice an identifier into a message the contract did not provide.
- No message names private data. The on-chain record set is public by design, so a
not foundcode is not a disclosure; the constraint is that the client-facing surface never grows toward commitment contents, metadata, or amounts, none of which are on-chain at all. See the Storage Model for the full on-chain data boundary.
| Code | Name | Enum | Domain | Status | Retry | HTTP |
|---|---|---|---|---|---|---|
| 1 | AlreadyInitialized |
ContractError |
common | returned | never | 409 |
| 2 | NotInitialized |
ContractError |
common | returned | after-operator-action | 500 |
| 20 | Unauthorized |
ContractError |
common | reserved | never | 403 |
| 40 | AlreadyExists |
ContractError |
common | reserved | never | 409 |
| 41 | NotFound |
ContractError |
common | reserved | after-caller-change | 404 |
| 42 | InvalidState |
ContractError |
common | reserved | never | 400 |
| 60 | InvalidInput |
ContractError |
common | returned | after-caller-change | 400 |
| 61 | InvalidAddress |
ContractError |
common | returned | after-caller-change | 400 |
| 62 | IncompatibleInterfaceVersion |
ContractError |
common | returned | after-caller-change | 400 |
| 64 | BatchTooLarge |
ContractError |
common | returned | after-caller-change | 400 |
| 80 | ProtocolPaused |
ContractError |
common | reserved | after-operator-action | 503 |
| 90 | NoUpgradeApproval |
ContractError |
common | returned | after-operator-action | 403 |
| 91 | UpgradeTimelockNotElapsed |
ContractError |
common | returned | after-operator-action | 409 |
| 92 | UpgradeApprovalExpired |
ContractError |
common | returned | after-operator-action | 409 |
| 93 | WasmHashMismatch |
ContractError |
common | returned | after-caller-change | 400 |
| 94 | InvalidTimingConfig |
ContractError |
common | returned | after-caller-change | 400 |
| 95 | ThresholdApprovalRequired |
ContractError |
common | returned | after-operator-action | 403 |
| 96 | ApprovalProposalNotFound |
ContractError |
common | returned | after-caller-change | 404 |
| 97 | ApprovalProposalExpired |
ContractError |
common | returned | after-operator-action | 409 |
| 98 | InsufficientApprovals |
ContractError |
common | returned | after-operator-action | 403 |
| 99 | InvalidApprovalPolicy |
ContractError |
common | returned | after-caller-change | 400 |
| 200 | IssuerAlreadyRegistered |
IssuerError |
issuer-registry | returned | never | 409 |
| 201 | IssuerNotFound |
IssuerError |
issuer-registry | returned | after-caller-change | 404 |
| 202 | IssuerAddressAlreadyRegistered |
IssuerError |
issuer-registry | returned | never | 409 |
| 203 | IssuerAddressNotFound |
IssuerError |
issuer-registry | returned | after-caller-change | 404 |
| 204 | IssuerRevoked |
IssuerError |
issuer-registry | returned | never | 403 |
| 205 | IssuerInactive |
IssuerError |
issuer-registry | reserved | after-operator-action | 403 |
| 206 | InvalidTransition |
IssuerError |
issuer-registry | returned | never | 400 |
| 207 | InvalidAddress |
IssuerError |
issuer-registry | returned | after-caller-change | 400 |
| 208 | IssuerCapacityExceeded |
IssuerError |
issuer-registry | returned | after-operator-action | 409 |
| 209 | MaxBelowActiveUsage |
IssuerError |
issuer-registry | returned | after-caller-change | 400 |
| 210 | ReactivationCooldownActive |
IssuerError |
issuer-registry | returned | after-caller-change | 400 |
| 211 | InvalidMetadataCommitment |
IssuerError |
issuer-registry | returned | after-caller-change | 400 |
| 212 | BatchTooLarge |
IssuerError |
issuer-registry | returned | after-caller-change | 400 |
| 300 | ProofAlreadyRegistered |
ProofError |
proof-registry | returned | never | 409 |
| 301 | ProofNotFound |
ProofError |
proof-registry | returned | after-caller-change | 404 |
| 302 | ProofAlreadyRevoked |
ProofError |
proof-registry | returned | never | 400 |
| 303 | ProofExpired |
ProofError |
proof-registry | returned | after-caller-change | 400 |
| 304 | InvalidSchemaVersion |
ProofError |
proof-registry | returned | after-caller-change | 400 |
| 305 | SchemaVersionNotApproved |
ProofError |
proof-registry | reserved | after-operator-action | 400 |
| 306 | InvalidAddress |
ProofError |
proof-registry | returned | after-caller-change | 400 |
| 307 | ContractPaused |
ProofError |
proof-registry | returned | after-operator-action | 503 |
| 308 | IssuerInactive |
ProofError |
proof-registry | returned | after-operator-action | 403 |
| 309 | UnsupportedSchema |
ProofError |
proof-registry | returned | after-operator-action | 400 |
| 310 | MalformedInput |
ProofError |
proof-registry | returned | after-caller-change | 400 |
| 311 | InvalidBatchSize |
ProofError |
proof-registry | returned | after-caller-change | 400 |
| 312 | InvalidActivationTime |
ProofError |
proof-registry | returned | after-caller-change | 400 |
| 313 | DisputeAlreadyOpen |
ProofError |
proof-registry | returned | never | 409 |
| 314 | DisputeNotFound |
ProofError |
proof-registry | returned | after-caller-change | 404 |
| 315 | DisputeNotOpen |
ProofError |
proof-registry | returned | never | 400 |
| 316 | UnsupportedProofType |
ProofError |
proof-registry | returned | after-operator-action | 400 |
| 317 | InvalidProofContext |
ProofError |
proof-registry | reserved | after-caller-change | 400 |
| 318 | ProofCapacityReached |
ProofError |
proof-registry | returned | after-operator-action | 409 |
| 319 | ProofAccountingUnavailable |
ProofError |
proof-registry | returned | after-operator-action | 503 |
| 320 | ProofCountOverflow |
ProofError |
proof-registry | returned | after-operator-action | 503 |
| 321 | CyclicSupersession |
ProofError |
proof-registry | returned | never | 400 |
| 322 | CrossIssuerSupersession |
ProofError |
proof-registry | returned | never | 403 |
| 323 | PredecessorNotFound |
ProofError |
proof-registry | returned | after-caller-change | 404 |
| 324 | TooManySuccessors |
ProofError |
proof-registry | returned | never | 400 |
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: never
- Cause: initialize was called on a contract that already has an admin.
- Remediation: Treat the deployment as already provisioned. Verify the recorded admin before assuming the deployment is the one you expected.
- Suggested HTTP status: 409
- Client message: "Contract is already initialized"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: A call read instance state on a contract that was never initialized.
- Remediation: Initialize the contract, or point the client at the correct deployed address. Do not retry against the same uninitialized contract.
- Suggested HTTP status: 500
- Client message: "Service temporarily unavailable"
- Enum:
ContractError - Domain: common
- Status: reserved
- Retry: never
- Cause: Reserved for an explicit authorization rejection. The contracts currently enforce authorization through require_auth, which aborts the invocation with a host authorization error rather than returning this code.
- Remediation: Sign with the address the operation requires. Clients must treat a host authorization abort and this code as the same outcome, and neither reveals which address would have been accepted.
- Suggested HTTP status: 403
- Client message: "Insufficient permissions"
- Enum:
ContractError - Domain: common
- Status: reserved
- Retry: never
- Cause: Reserved for a generic duplicate-write rejection. The registries return their own specific codes instead: 200, 202, and 300.
- Remediation: Read the existing record instead of rewriting it. Handle the specific codes 200, 202, and 300, and treat this one as a forward-compatible synonym.
- Suggested HTTP status: 409
- Client message: "Resource already exists"
- Enum:
ContractError - Domain: common
- Status: reserved
- Retry: after-caller-change
- Cause: Reserved for a generic missing-record rejection. The registries return their own specific codes instead: 201, 203, and 301.
- Remediation: Confirm the identifier hash was derived with the documented hashing rules. Handle the specific codes 201, 203, and 301, and treat this one as a forward-compatible synonym.
- Suggested HTTP status: 404
- Client message: "Resource not found"
- Enum:
ContractError - Domain: common
- Status: reserved
- Retry: never
- Cause: Reserved for a generic lifecycle rejection. The issuer registry returns 204 and 206 instead, and the proof registry returns 302.
- Remediation: Read the current status and choose an operation the lifecycle allows. Handle the specific codes 204, 206, and 302, and treat this one as a forward-compatible synonym.
- Suggested HTTP status: 400
- Client message: "Operation not permitted in current state"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: An argument failed validation, such as a zero schema version.
- Remediation: Correct the argument. Retrying the identical request will fail identically.
- Suggested HTTP status: 400
- Client message: "Invalid input provided"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: A supplied address is not a valid non-sentinel account or contract address.
- Remediation: Supply a canonical Stellar account or contract address that is not reserved as a sentinel.
- Suggested HTTP status: 400
- Client message: "Invalid address"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: A cross-contract dependency reported an interface version outside the range the consumer accepts, during initialization or a governed dependency replacement.
- Remediation: Bind a dependency whose interface version is compatible: same major and at least the minor and patch the consumer requires. Read the accepted version from the consumer before retrying.
- Suggested HTTP status: 400
- Client message: "Incompatible dependency version"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: get_schema_statuses was given more schema versions than the bounded batch limit.
- Remediation: Split the request into batches of at most MAX_SCHEMA_STATUS_BATCH entries.
- Suggested HTTP status: 400
- Client message: "Request batch is too large"
- Enum:
ContractError - Domain: common
- Status: reserved
- Retry: after-operator-action
- Cause: Reserved for the pause rejection. A paused protocol is currently reported by the proof registry as 304, not as this code.
- Remediation: Poll is_paused rather than waiting for this code: a paused protocol surfaces as 304 in the current release. Treat both as the same operator-action outcome.
- Suggested HTTP status: 503
- Client message: "Service temporarily paused"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: An upgrade was attempted without a recorded approval.
- Remediation: Have the authorized admin approve the target WASM and version before retrying.
- Suggested HTTP status: 403
- Client message: "No upgrade approval was found"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: The approved upgrade was attempted before its earliest execution ledger.
- Remediation: Wait until the approval's earliest execution ledger, then retry with the approved hash and version.
- Suggested HTTP status: 409
- Client message: "Upgrade timelock has not elapsed"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: The approved upgrade was attempted at or after its expiration ledger.
- Remediation: Request a fresh upgrade approval and retry within its execution window.
- Suggested HTTP status: 409
- Client message: "Upgrade approval has expired"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: The upgrade supplied a WASM hash different from the approved hash.
- Remediation: Install the exact WASM artifact whose hash was approved, or obtain approval for the intended artifact.
- Suggested HTTP status: 400
- Client message: "WASM hash does not match approval"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: An upgrade or governance timing configuration has inconsistent or invalid ledger bounds.
- Remediation: Choose valid timing values whose activation and expiry bounds are ordered and representable.
- Suggested HTTP status: 400
- Client message: "Invalid timing configuration"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: A critical action requires a threshold-approved proposal instead of direct execution.
- Remediation: Create a proposal for the canonical action, collect the configured signer threshold, and execute that proposal.
- Suggested HTTP status: 403
- Client message: "Threshold approval is required"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: The requested critical-action proposal does not exist or has already been consumed.
- Remediation: Use an existing proposal identifier for this contract, or create a new proposal.
- Suggested HTTP status: 404
- Client message: "Approval proposal not found"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: The critical-action proposal reached its expiry ledger before execution.
- Remediation: Create a new proposal and collect approvals again.
- Suggested HTTP status: 409
- Client message: "Approval proposal has expired"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-operator-action
- Cause: The proposal has fewer unique authorized signer approvals than its policy threshold.
- Remediation: Collect approvals from additional configured signers before execution.
- Suggested HTTP status: 403
- Client message: "Approval threshold has not been reached"
- Enum:
ContractError - Domain: common
- Status: returned
- Retry: after-caller-change
- Cause: The approval policy has an invalid threshold, signer count, or duplicate signer.
- Remediation: Configure a non-empty unique signer set with a threshold between one and the signer count.
- Suggested HTTP status: 400
- Client message: "Invalid approval policy"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: never
- Cause: register_issuer was called with an issuer_id_hash that already has a record.
- Remediation: Use update_issuer to change metadata, or rotate_issuer_address to change the address. Registration is one-time per identifier.
- Suggested HTTP status: 409
- Client message: "Issuer already registered"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: A call referenced an issuer_id_hash with no record, or the registry has no admin yet.
- Remediation: Register the issuer first, or confirm the identifier hash. If the registry is uninitialized, every call returns this code until an admin is set.
- Suggested HTTP status: 404
- Client message: "Issuer not found"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: never
- Cause: A registration or rotation targeted a Stellar address already bound to an issuer.
- Remediation: Choose an unused address. An address maps to at most one issuer so that address-based lookups stay unambiguous.
- Suggested HTTP status: 409
- Client message: "Issuer address already registered"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: An address lookup found no entry in the reverse index.
- Remediation: The address is not a registered issuer. Note that a rotated-away address returns this code, because the old index entry is removed.
- Suggested HTTP status: 404
- Client message: "Issuer address not found"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: never
- Cause: The operation targeted an issuer whose status is Revoked.
- Remediation: Revocation is terminal. Register a new issuer identifier if the party is to be readmitted.
- Suggested HTTP status: 403
- Client message: "Issuer has been revoked"
- Enum:
IssuerError - Domain: issuer-registry
- Status: reserved
- Retry: after-operator-action
- Cause: Reserved for the suspended-issuer rejection. A suspended issuer is currently reported by the proof registry as 304, not as this code.
- Remediation: Call is_active_address before registering rather than waiting for this code: a suspended issuer surfaces as 304 in the current release. An admin must reactivate the issuer; suspension is reversible, revocation is not.
- Suggested HTTP status: 403
- Client message: "Issuer is not active"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: never
- Cause: A status change was requested that the lifecycle does not allow, such as reactivating a revoked issuer.
- Remediation: Read the current status and choose a permitted transition.
- Suggested HTTP status: 400
- Client message: "Invalid status transition"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: Issuer registration, rotation, or lifecycle input contains an invalid address or reserved empty commitment.
- Remediation: Supply a canonical issuer address and nonzero commitment values required by the selected operation.
- Suggested HTTP status: 400
- Client message: "Invalid issuer address or commitment"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-operator-action
- Cause: register_issuer or reactivate_issuer would push the active-issuer count above the governed maximum capacity.
- Remediation: Wait for an issuer to be suspended or revoked, or have an admin raise the maximum active-issuer capacity. Read get_active_issuer_count and get_max_active_issuers to see the headroom.
- Suggested HTTP status: 409
- Client message: "Issuer capacity reached"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: set_max_active_issuers was asked to set a limit below the current active-issuer count without the explicit below-usage override.
- Remediation: Pass a limit at or above the current active count, or set the override flag to ratchet the ceiling down deliberately. Retrying the identical request will fail identically.
- Suggested HTTP status: 400
- Client message: "Capacity limit below current usage"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: reactivate_issuer was called before the suspended issuer's reactivation cooldown had elapsed.
- Remediation: Wait until the ledger time returned by get_earliest_reactivation before retrying. The deadline is fixed at suspension time and does not move.
- Suggested HTTP status: 400
- Client message: "Reactivation cooldown has not elapsed"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: set_issuer_metadata_commitment was called with the all-zero digest for the content hash or the URI hash, which is reserved as the "no URI commitment recorded" sentinel.
- Remediation: Compute a real SHA-256 commitment over the canonical document or URI bytes and resubmit; the all-zero digest is never accepted.
- Suggested HTTP status: 400
- Client message: "Invalid identity digest"
- Enum:
IssuerError - Domain: issuer-registry
- Status: returned
- Retry: after-caller-change
- Cause: get_issuer_statuses was given more issuer identifiers than the bounded batch limit.
- Remediation: Split the request into batches of at most MAX_ISSUER_STATUS_BATCH entries.
- Suggested HTTP status: 400
- Client message: "Request batch is too large"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: register_proof was called with a proof_id_hash that already has a record.
- Remediation: Proof records are immutable once written, including after archival and restoration. Register a new identifier rather than replacing a commitment.
- Suggested HTTP status: 409
- Client message: "Proof already registered"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: A call referenced a proof_id_hash with no record, or the proof registry has no instance state to read its dependencies from.
- Remediation: Confirm the identifier hash. If register_proof returns this code, the registry itself is uninitialized and no write took place.
- Suggested HTTP status: 404
- Client message: "Proof not found"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: A revocation targeted a proof already in the Revoked state.
- Remediation: Treat the revocation as complete. Revocation is terminal and idempotent in effect, though not in return value.
- Suggested HTTP status: 400
- Client message: "Proof already revoked"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: register_proof was given an expires_at at or before the current ledger timestamp.
- Remediation: Send an expiration in the future relative to ledger time, not to wall-clock time on the calling host.
- Suggested HTTP status: 400
- Client message: "Invalid proof expiration"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: register_proof was given schema version zero.
- Remediation: Use a nonzero schema version. Check protocol pause, issuer activity, schema approval, and proof-type approval separately when registration is rejected.
- Suggested HTTP status: 400
- Client message: "Invalid schema version"
- Enum:
ProofError - Domain: proof-registry
- Status: reserved
- Retry: after-operator-action
- Cause: The schema version is non-zero but is not approved in protocol-config, either because it was never approved or because it was deprecated.
- Remediation: A protocol operator must approve the version. A registry pointed at an uninitialized protocol config also returns UnsupportedSchema (309).
- Suggested HTTP status: 400
- Client message: "Schema version not approved"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: The issuer address is not a valid issuing address for this proof registry.
- Remediation: Supply an active issuer account address distinct from the proof registry and its configuration dependencies.
- Suggested HTTP status: 400
- Client message: "Invalid issuer address"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: The proof registry detected that the protocol is paused and rejected proof registration.
- Remediation: Call is_paused on the protocol config contract to check if the pause is active. An operator must unpause the protocol to allow proof registration to resume.
- Suggested HTTP status: 503
- Client message: "Contract is paused"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: The issuer address is not active or was suspended.
- Remediation: Call is_active_address on the issuer registry to confirm the issuer is active. An operator must reactivate the issuer if it was suspended.
- Suggested HTTP status: 403
- Client message: "Issuer is not active"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: The proof schema identifier is not supported or not registered in the protocol config.
- Remediation: Call is_schema_version_approved on the protocol config contract to verify the schema version is approved. An operator must approve the schema version before it can be used for proof registration.
- Suggested HTTP status: 400
- Client message: "Schema not supported"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: register_proof_with_payload was given an auxiliary payload larger than the schema's governed limit (protocol-config's get_schema_payload_limit for that version).
- Remediation: Call get_schema_payload_limit for the schema version and shrink the payload to fit, or use register_proof without a payload if none is required.
- Suggested HTTP status: 400
- Client message: "Malformed proof input"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: A batch registration or batch revocation call was given zero entries, or more entries than MAX_PROOF_BATCH_SIZE.
- Remediation: Split the request into batches of between one and MAX_PROOF_BATCH_SIZE entries.
- Suggested HTTP status: 400
- Client message: "Invalid batch size"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: register_proof_with_activation was given an activates_at at or after expires_at, so the proof could never be valid.
- Remediation: Choose an activation time strictly before the expiration.
- Suggested HTTP status: 400
- Client message: "Invalid activation time"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: open_dispute was called for a proof that already has an Open dispute.
- Remediation: Withdraw, resolve, or reject the existing dispute before opening a new one. Retrying the identical request will not help: the dispute is cleared by a different call (from the disputant or the admin), not by this one succeeding on its own.
- Suggested HTTP status: 409
- Client message: "A dispute is already open for this proof"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: withdraw_dispute, resolve_dispute, or reject_dispute referenced a proof with no dispute record.
- Remediation: Open a dispute first, or confirm the proof id.
- Suggested HTTP status: 404
- Client message: "No dispute found for this proof"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: A dispute transition was attempted on a dispute that is not Open (already withdrawn, resolved, or rejected).
- Remediation: Read the dispute's current status; it is terminal once withdrawn, resolved, or rejected.
- Suggested HTTP status: 400
- Client message: "Dispute is not open"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: The proof type identifier is not supported by the protocol config.
- Remediation: Call is_proof_type_approved on the protocol config contract to verify the proof type is approved. An operator must approve the proof type before it can be used for proof registration.
- Suggested HTTP status: 400
- Client message: "Proof type not supported"
- Enum:
ProofError - Domain: proof-registry
- Status: reserved
- Retry: after-caller-change
- Cause: The network passphrase or native/issued asset identifier is not canonical, or the passphrase does not match the ledger network.
- Remediation: Use the exact active Stellar network passphrase and either Native or a case-sensitive ASCII alphanumeric asset code with a valid account issuer.
- Suggested HTTP status: 400
- Client message: "Invalid proof network or asset context"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: The proof registry has reached its configured capacity.
- Remediation: An operator must increase the proof capacity or archive eligible proofs before registration can continue.
- Suggested HTTP status: 409
- Client message: "Proof registry capacity reached"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: Stored proof counts are missing or inconsistent, so an accounting operation cannot proceed safely.
- Remediation: Reconcile proof counts and verify the reported counters before retrying the operation.
- Suggested HTTP status: 503
- Client message: "Proof accounting is unavailable"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-operator-action
- Cause: A proof count cannot be incremented without overflowing its storage type.
- Remediation: Reconcile the proof counters or raise the configured capacity before registering more proofs.
- Suggested HTTP status: 503
- Client message: "Proof count limit reached"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: The proof identifier matches its own predecessor or would create a supersession cycle.
- Remediation: A proof cannot supersede itself or create a cycle. Register the renewal as a forward link from an existing proof.
- Suggested HTTP status: 400
- Client message: "Cyclic supersession detected"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: The predecessor proof was registered by a different issuer.
- Remediation: Cross-issuer supersession is rejected unless protocol policy explicitly supports it.
- Suggested HTTP status: 403
- Client message: "Cross-issuer supersession rejected"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: after-caller-change
- Cause: The specified predecessor proof was not found.
- Remediation: Ensure the predecessor proof exists and remains historically queryable.
- Suggested HTTP status: 404
- Client message: "Predecessor proof not found"
- Enum:
ProofError - Domain: proof-registry
- Status: returned
- Retry: never
- Cause: The predecessor proof already has the maximum number of successors.
- Remediation: A predecessor can only have a bounded number of successors.
- Suggested HTTP status: 400
- Client message: "Too many successors"