PATINA docs

Reason codes

Eighteen codes, frozen. Every one of them means a transaction confirmed on Bitcoin and the protocol declined to act on it. None of them means you lost coins.

What you will know after this page
  • Where an invalid event surfaces, and what it names: the transaction, the height, the output when there is one, and a single code.
  • All seven SEED codes, and what to change before you build a new commit.
  • Which KEEP codes void one entry and which throw the whole marker away.
  • The four codes that fire before any opcode rule runs.
  • What a code you do not recognise tells you, and which two status fields to compare when you see one.

Where you see them

GET /patina/invalid-events

Each event names the transaction, the height, and one code. If your mint did not appear, this is where the explanation is.

SEED codes

One code per SEED check. The reveal confirmed whatever the protocol made of it, and the commit it spent cannot be spent twice, so a retry starts again from a new salt and a new commit.

Failures while creating an artifact. In all seven, nothing is created and your coins are in the outputs your reveal made.
CodeWhat the parser sawWhat it means for you
SEED_BAD_GRAMMAR The marker did not decode as a SEED: wrong payload length, a non minimal push, more than one push, extra opcodes, or a flags byte that is not zero A construction bug. Compare your script against the byte table on Marker grammar and try again with a new commit.
SEED_NO_COMMIT_INPUT No input revealed a qualifying commit leaf You spent the commit by the key path instead of the script path, or the leaf script did not match byte for byte. Retry with a new commit.
SEED_COMMITMENT_MISMATCH A commit leaf was revealed, but SHA256("PTNA/commit" || key || salt) did not equal the commitment in the leaf The salt in the marker is not the salt you committed to, or the key differs. Check both. Retry with a new commit.
SEED_COMMIT_TOO_YOUNG Fewer than 144 blocks between the commit output's block and the reveal's block You revealed early. The commit is spent and the claim is gone. Retry with a new commit and count the blocks.
SEED_CARRIER_OUT_OF_RANGE carrier_vout names an output index that does not exist Off by one in the marker payload. Retry.
SEED_CARRIER_IS_OPRETURN carrier_vout pointed at a data output You pointed the artifact at the marker itself. Retry.
SEED_CARRIER_BELOW_MIN The carrier held less than 100000 sats for a founding claim, or less than 10000 sats otherwise Underfunded carrier, often because fees came out of the wrong output. Retry with more in the carrier.

KEEP codes

Two sizes of failure sit in this table. The four KEEP_ENTRY codes void one entry and leave the rest of the marker working. KEEP_BAD_GRAMMAR and KEEP_DUPLICATE_INPUT are decode failures that discard the whole marker, and KEEP_NO_CARRIER_INPUT means there was nothing to route to begin with. The public risks page shows the same two sizes side by side.

Failures while routing a spend. The spend still happened. Only the routing instruction was ignored.
CodeWhat the parser sawWhat it means for you
KEEP_BAD_GRAMMAR count was zero, above 8, or the payload length did not match count The whole KEEP marker is ignored. Every carrier in the transaction followed the default rule. Check where each artifact landed.
KEEP_NO_CARRIER_INPUT The transaction carried a KEEP marker but spent no carrier at all Nothing happened. The marker was pointless, not harmful.
KEEP_ENTRY_NOT_CARRIER An entry named an input that does not spend a carrier That entry is void. Other valid entries still apply.
KEEP_ENTRY_OUT_OF_RANGE An entry named a vout that does not exist Entry void, default rule applies to that carrier. Check where the artifact went.
KEEP_ENTRY_IS_OPRETURN An entry named a data output Entry void, default rule applies.
KEEP_ENTRY_BELOW_MIN An entry named an output holding less than 10000 sats Entry void, default rule applies. This is the common one: the intended destination was too small.
KEEP_DUPLICATE_INPUT Two entries named the same input index An ambiguous instruction is a decode failure, so the whole marker is inert. Every carrier in the transaction followed the default rule. Check where each artifact landed.

Marker codes

These four come from the layer above the opcodes. In all four the transaction is treated as carrying no usable marker, so a SEED creates nothing and a carrier spend falls to the default rule.

Failures before the opcode is even considered.
CodeWhat the parser sawWhat it means for you
VOID_DUPLICATE_MARKER More than one output had a payload starting with PTNA The transaction is treated as unmarked. A SEED creates nothing. A carrier spend follows the default rule.
MARKER_UNKNOWN_OP The opcode byte was not 0x01 or 0x02 Nothing happened. Either a construction bug, or a future opcode your indexer does not implement.
MARKER_UNKNOWN_VERSION The version byte was not 0x01 Nothing happened. Same two possibilities.
MARKER_TOO_LARGE The scriptPubKey exceeded 83 bytes, or the push payload exceeded 80 Nothing happened. No legal marker is anywhere near that size, so this is a construction bug.

Codes are frozen

This list of eighteen is part of the baseline. An implementation must not invent codes, rename them, or merge two into one. If you find a failure case that none of these describe, that is a specification gap and it should be reported, not papered over with a nineteenth code.

Two consequences for operators:

  • Seeing a code you do not recognise means your software is older or newer than the one that produced the event. Check spec_sha256 and parser_version from GET /patina/status on both sides.
  • Codes are part of what implementations must agree on. Same chain, same codes, in the same order. See Golden vectors and state roots.

What none of these codes mean

  • They never mean your bitcoin moved somewhere you did not send it.
  • They never mean an artifact was taken from you.
  • They never mean a transaction was rejected by Bitcoin. Every one of these transactions confirmed normally. The protocol simply declined to interpret it.