Chio/Docs
LOGIN · JOIN

PlatformOperations & Walkthrough

Swarm

Swarm Denial Codes

One refusal carries three different names depending on where you caught it. Each name indexes back to the check that produced it.

Source

This page reflects crates/kernel/chio-swarm-authority/src/verifier.rs and its three submodules, verifier/witness.rs, verifier/util.rs, and verifier/budget_accounting.rs, in the chio repository. A refusal carries a message rather than a schema, so the source of truth is the code that produces it. The Swarm Protocol reference carries the artifact set, the verification order, and the invariants a valid bundle satisfies; every mechanism column below links the page that shows what the named artifact looks like when it is correct.

The runtime side comes from crates/kernel/chio-runtime-core/src/admission_hook/swarm_authority.rs, which wraps the verifier and assigns a failure code, and crates/kernel/chio-runtime-core/src/schema.rs, which declares the code registry. The two variants a refusal can take are declared in crates/kernel/chio-swarm-authority/src/error.rs.

Nothing in this family is a registry code. spec/errors/registry.yaml declares 20 URN domains and 111 codes, and no domain among them is a swarm domain. A swarm refusal reaches an operator as one of the three names below instead.


Three names for one refusal

A swarm delegation is refused by one function, verify_swarm_authority_bundle, which returns SwarmAuthorityError::Rejected(String) carrying a sentence. That sentence reaches an operator under three different identities, and which one you get depends entirely on which call site refused:

  • A runtime failure code. On the admission path the sentence is discarded and replaced by one of twelve stable snake-case codes in chio-runtime-core. The verifier writes most of its refusals out as sentences and generates the rest from field labels, and every one of them collapses into a single code: chio_swarm_authority_rejected.
  • The verifier message, verbatim. chio proof verify prints it as proof verify: <message>. The proof room wraps it two ways: the source-verifier route emits proof-room.source-verifier.failed: <message>, and the fixture route emits proof-room.fixture.verify-failed: <fixture_id>: <message>.
  • A proof-room negative slug. The doctor derives proof-room.negative.<slug> from the message so a negative fixture can pin a failure without pinning punctuation.

None of the three is a stable API in the sense a caller usually wants. The failure codes are stable strings but coarse; the messages are exact but unversioned; the slugs are derived from the messages and move when a message is reworded. The crate says so itself: its error type has two variants and no code enum. Use the tables below to look a refusal up; a caller that needs a stable value reads the runtime failure code.

The runtime keeps the code and drops the sentence

The admission hook destructures the rejection with Err(ChioRuntimeError::Rejected { code, .. }) and builds its denial metadata from the code alone. runtime_denial_metadata carries admission_id, accepted: false, and failure_code, and nothing else. A denied swarm request therefore tells you that a bundle failed, never which verifier message it failed on. To recover the sentence, run the same bundle through chio proof verify. Two later branches do append fields to this object: a consume failure adds the ambiguity keys, and a replay denial adds whatever denial_metadata_after_release records about releasing the treaty reservation. Neither adds the verifier sentence.

Where each name is produced

chio-swarm-authority/src/verifier.rs and its two submodules, verifier/witness.rs and verifier/util.rs, hold every verifier message. chio-runtime-core/src/admission_hook/swarm_authority.rs wraps the verifier with the checks only a runtime can make, assigns codes, and adds the eight route-metadata messages that have no proof-path equivalent. chio-runtime-core/src/schema.rs declares the code registry. The stores contribute the replay and duplicate-insert codes.

Nothing here runs unless the request asks for it. swarm_ref_from_request returns Ok(None) when the request carries no governed intent, no context, or no chioSwarm key, and the hook then skips the whole sequence. Unlike the treaty path, which denies a federated request whose treaty context disappeared, there is no condition under which the runtime requires a request to declare a swarm context. Swarm admission is opt-in per request.

rendering
Pre-dispatch order for one swarm-bound request. Route metadata is compared before the bundle is verified, so a metadata mismatch is reported even on a bundle that would have failed verification anyway.
sourcecrates/kernel/chio-runtime-core/src/admission_hook/swarm_ref.rs:22-109crates/kernel/chio-runtime-core/src/admission_hook/swarm_authority.rs:21-43crates/kernel/chio-runtime-core/src/admission_hook.rs:877-944at fe56570

The reference check is the runtime-only part and it is worth being exact about. Each of the seven references in the chioSwarm context carries an id and a SHA-256. The id must equal the stored artifact’s own id field, and the digest must equal canonical_sha256 of the stored artifact, not of the bytes the request supplied. The request names evidence; it never carries it.

Each reference is accepted in two shapes. A nested object under a name like taskGraph reads id (or evidenceId or artifactId) plus sha256 (or artifactSha256); a flat pair like taskGraphId and taskGraphSha256 is read only if the nested form is absent. Several names have aliases: continuation, routePlan, witnessChain, witness, and budgetLease are all accepted.

Every expiry and freshness rule below reads bundle.now_unix_ms, and the caller always overwrites that field before verifying. The runtime hook sets it to the admission clock; the CLI and proof room set it to wall clock at verification. A value baked into a stored bundle never decides staleness.

crates/kernel/chio-runtime-core/src/admission_hook/swarm_authority.rsrust
if reference.evidence_id != stored_id
    || reference.artifact_sha256 != canonical_sha256(stored_artifact)?
{
    return rejected(
        "chio_swarm_authority_ref_mismatch",
        "swarm-bound request evidence hash does not match verifier-owned authority evidence",
    );
}

There is a second runtime path with different behavior. revalidate_before_dispatch re-runs the whole reference and verification sequence after admission and before the call actually goes out. It does not deny; it returns KernelError::Internal with runtime swarm reference revalidation failed: {code} or runtime swarm authority revalidation failed: {error}. The second of those formats the whole ChioRuntimeError, whose Display is runtime admission rejected: {code}: {detail}. That is the one place on the runtime path where the verifier’s own sentence survives, and it only happens for a bundle that changed between admission and dispatch. A reservation that changed under it reports runtime admission reservation reserved_swarm_continuation_id changed before dispatch.


The runtime failure codes

Twelve codes in CHIO_RUNTIME_FAILURE_CODES name swarm state, plus two smuggling codes the swarm context shares with the treaty context. This is the complete set of swarm-specific values for metadata.chio_runtime.failure_code. A swarm-bound request is still subject to every other code in the registry: it can be denied for a missing governed intent, a treaty failure, or a pheromone policy verdict without any swarm-named code appearing. The last three rows are store-side codes raised on insert or on state validation, so they normally reach a caller as an error from the store API rather than as denial metadata.

Failure codeProduced whenNext
invalid_chio_swarm_contextThe chioSwarm key exists on the governed intent but is not a JSON object.Fix the caller. Nothing was read.
request_smuggled_trust_rootThe context carries any of trustRoot, trustRoots, trustBundle, authorityBundle, signingKey, witnessKeys.Trust is verifier-owned. Remove the key; there is no override.
request_smuggled_dynamic_trustThe context carries dynamicTrust, dynamicTrustBundle, or peerDiscovery.Same. Checked before any reference is parsed.
missing_chio_swarm_evidence_refOne of the seven references is absent, or present without both an id and a digest.All seven are mandatory: task graph, continuation token, route-plan receipt, delegation witness, join receipt, revocation epoch, budget pool.
invalid_chio_swarm_evidence_refA named reference is not a JSON object, its id trims to empty, or its digest is not exactly 64 ASCII hex characters. This shape check is chio-runtime-core’s own is_sha256_hex, which does not reject uppercase.Send the canonical digest of the stored artifact, lowercase. An uppercase digest passes this check and then fails the comparison as chio_swarm_authority_ref_mismatch, because canonical_sha256 emits lowercase.
missing_chio_swarm_authority_bundleNo bundle is stored under the referenced task-graph id, or the store did not override swarm_authority_bundle at all: the trait default returns Ok(None).The bundle reaches the store through insert_swarm_authority_bundle. The chio-runtime store adapters forward that call, and every caller that originates one is a test.
chio_swarm_authority_ref_mismatchA referenced id or canonical digest disagrees with the stored artifact; a referenced artifact is absent from the stored bundle; or the continuation names a different route plan than the request did.Re-read the stored bundle and recompute digests. The request is naming the wrong evidence, not carrying bad evidence.
chio_swarm_authority_rejectedRoute metadata did not match the route-plan receipt, or the verifier refused the bundle for any reason at all.The code does not narrow it. Run chio proof verify on the bundle to get the sentence, then use the tables below.
chio_swarm_continuation_replayA single-use continuation id was already consumed. Every store arm agrees: in-memory set insert, JSON list scan, and SQLite INSERT OR IGNORE returning zero rows.Mint a new token. Continuation Tokens covers the lifecycle and the resumable exemption.
chio_swarm_continuation_store_unsupportedThe admission store did not override consume_swarm_continuation or release_swarm_continuation, so the trait default refuses. The detail names which operation.A store that cannot track replay denies rather than passing the request through. Use a store that implements it.
swarm_continuation_consume_errorConsumption failed for a reason that is not replay, including a caught panic.Ownership is ambiguous. The metadata adds ambiguous_swarm_continuation_id, reservation_ownership_ambiguous: true, and reservation_consumption_failure_reason. Treat the id as burned.
runtime_swarm_authority_empty_graph_idA bundle is inserted with an empty or whitespace-only task_graph.graph_id. All three backends check on insert; SQLite also checks on lookup, and the JSON store re-checks every stored bundle in validate_state.Store-side, not request-side. Fix the writer.
duplicate_swarm_authority_bundle_mismatchA second bundle is inserted under an existing graph id with a different canonical digest. An identical re-insert is idempotent and returns success.Graph ids are the store’s primary key. Re-key the graph or delete the old bundle.
duplicate_consumed_swarm_continuationThe JSON store’s state validation found the same consumed continuation id twice in its own file.The file was edited or merged. Raised at load and after every mutation, so a corrupt file fails closed rather than persisting.

One emitted code is not in the registry

JsonRuntimeAdmissionStore::validate_state raises duplicate_swarm_authority_bundle, without the _mismatch suffix, when its state file repeats a graph id. That string is not in CHIO_RUNTIME_FAILURE_CODES. The registry test asserts that the listed codes are present and that the list has no duplicates; it does not walk the crate to prove the converse, so an unregistered code ships without failing anything. Do not treat the registry as an exhaustive list of what a store can emit.

Verifier messages, by artifact

Everything below arrives at the runtime as chio_swarm_authority_rejected and at the proof paths verbatim. Placeholders are shown as the variable the code interpolates. Since these are refusals to accept already-signed evidence, the operator action is uniform: re-mint the named artifact so it satisfies the rule, then re-present the bundle. The mechanism column is therefore also the fix.

Deriving the negative slug

semantic_negative_failure_code first takes whatever follows proof verify: and truncates at the first (. Then stable_negative_failure_code strips any prefix in a fixed list of about thirty (for this family, swarm authority invalid: and proof-room.source-verifier.failed: ), strips everything after the first : unless the remainder already looks like a dotted code, lowercases, collapses every run of non-alphanumeric characters to a single hyphen, trims hyphens, and prefixes proof-room.negative.. An empty result falls back to proof-room.negative.unknown. So swarm route-plan receipt is stale: route-child-a becomes proof-room.negative.swarm-route-plan-receipt-is-stale, and the id drops out. A message with no : keeps everything, which is why the graph-cycle fixture pins proof-room.negative.swarm-task-graph-cycle-at-task-child-a with a task id baked into the slug. The strip list does not contain proof-room.fixture.verify-failed: , and that prefix parses as a dotted code, so a failure from the fixture route is returned unchanged and never becomes a proof-room.negative. slug at all.

Every negative fixture under fixtures/proof-room/swarm-authority/negatives/ carries an expected_failure_code slug and is registered in fixtures/proof-room/catalog.json as negative-transaction-passport, so chio proof doctor --scenario proof-package replays each one against the derived slug. Most of them are also listed in SWARM_AUTHORITY_CHECKS, where chio proof doctor --scenario swarm-authority matches a literal substring of the message instead. egress-constraint-unsupported and max-depth-exceeded are replayed under the proof-package scenario only.

The negative fixtures and their sentences

Each descriptor names a sibling directory holding the mutated bundle, so the whole set is one loop from a Chio checkout. scripts/proof-room-quickstart-env.sh exports the fixture trust anchors; cut -d' ' -f3- drops the error [urn:chio:error:cli:other]: prefix each line carries so the sentences line up.

swarm-authority · all-negativestranscript
$ source scripts/proof-room-quickstart-env.sh
$ for n in $(ls fixtures/proof-room/swarm-authority/negatives/*.json \
             | xargs -n1 basename | sed 's/\.json$//'); do
$   printf '%-30s ' "$n"
$   chio proof verify \
    "fixtures/proof-room/swarm-authority/$n/transaction-passport.json" \
    2>&1 | head -1 | cut -d' ' -f3-
$ done
budget-allocations-exceed-pool proof verify: swarm budget allocations exceed pool total
egress-constraint-unsupported  proof verify: unsupported swarm route-plan egress constraint: allow-private-network
graph-cycle                    proof verify: swarm task graph cycle at task-child-a
join-parent-set-mismatch       proof verify: swarm join receipt parent set mismatch: join-child-results
max-depth-exceeded             proof verify: swarm task exceeds max depth: task-child-a
replayed-continuation-nonce    proof verify: swarm continuation nonce replay: continuation-child-b
revoked-task                   proof verify: swarm task is revoked: task-child-a
route-plan-mismatch            proof verify: swarm route-plan selected route bridge mismatch: route-child-a
stale-continuation             proof verify: swarm continuation token is stale: continuation-child-a
stale-route-plan               proof verify: swarm route-plan receipt is stale: route-child-a
witness-child-scope-mismatch   proof verify: swarm witness child scope mismatch: witness-child-a
exit 1
Negative fixtureVerifier messageDoctor scenario
budget-allocations-exceed-poolswarm budget allocations exceed pool totalproof-package, swarm-authority
egress-constraint-unsupportedunsupported swarm route-plan egress constraint: allow-private-networkproof-package
graph-cycleswarm task graph cycle at task-child-aproof-package, swarm-authority
join-parent-set-mismatchswarm join receipt parent set mismatch: join-child-resultsproof-package, swarm-authority
max-depth-exceededswarm task exceeds max depth: task-child-aproof-package
replayed-continuation-nonceswarm continuation nonce replay: continuation-child-bproof-package, swarm-authority
revoked-taskswarm task is revoked: task-child-aproof-package, swarm-authority
route-plan-mismatchswarm route-plan selected route bridge mismatch: route-child-aproof-package, swarm-authority
stale-continuationswarm continuation token is stale: continuation-child-aproof-package, swarm-authority
stale-route-planswarm route-plan receipt is stale: route-child-aproof-package, swarm-authority
witness-child-scope-mismatchswarm witness child scope mismatch: witness-child-aproof-package, swarm-authority

Each message is the second identity in full: the verifier's own sentence, which chio proof verify prefixes with proof verify:. All but two name the artifact or task that failed, and that trailing id is the only place an operator gets it: the pool-total refusal names nothing, and the egress refusal names the rejected constraint value instead. The admission path reports each of them as chio_swarm_authority_rejected. Every invocation exits 1; the full stderr also carries a context object and a suggested fix line, dropped by head -1.

Field-shape messages, generated from a label

Four helpers in verifier/util.rs generate their messages from a template and a label, so the catalogue of them is short even though the call sites are many. The label names the field, and the template names the rule it broke.

TemplateHelperLabels
{label} must not be emptyrequire_non_empty59 distinct labels, one per required string field, for example swarm graph id, swarm planner subject, swarm continuation nonce, swarm witness attenuation rule.
{label} must be a lowercase sha256 digestrequire_sha25615 labels. The test is exactly 64 characters, ASCII hex, no uppercase. swarm task scope hash, swarm candidate set digest, swarm registry snapshot hash, swarm witness policy digest, and the rest.
duplicate {label}: {value}require_unique_strings15 labels over string lists. Also runs the emptiness check on every element first, so an empty entry reports as the first template, not this one.
swarm {label} graph id mismatchrequire_same_graphSix labels: route plan, join receipt, budget pool, continuation token, terminal receipt, witness chain. Every artifact must name the same graph.

The same file holds six *_signature_body helpers, one per signable family, and each can produce swarm {family} signature body invalid: {id} with or without a trailing : {error}. That is twelve more strings on the verification path, and they are listed here for completeness only: both arms require serde_json::to_value of a plain struct to fail or to return something other than an object. Delegation witnesses have no such helper, because witness_signature_body builds a typed struct and cannot fail.

Bundle level and trust

Denial stringProduced whenMechanism
trusted swarm witness keys missing: CHIO_SWARM_TRUSTED_WITNESS_KEYS must pin trusted swarm witness keysThe caller passed an empty key slice. require_trusted_witness_issuer_keys is the first line of verify_swarm_authority_bundle, before any artifact is validated. The bundle arrives deserialized, so this is not a parse gate. Six family-level ensure_*_issuer_is_pinned helpers inline the same check and the revocation epoch does not, but that asymmetry cannot be observed: the top-level check has already returned by then. Treat the six repeats as defensive, not as coverage the epoch lacks.Swarm Authority
signed swarm delegation evidence missing: continuation tokens and witness chains are requiredcontinuation_tokens is empty or witness_chains is empty. Either list alone denies. Denied so that verified cannot mean two different claim sets. Checked fourth, after the key-slice precondition, the task graph, and the graph signature.Swarm Authority
swarm witness issuer did:chio is not self-certifyingAn issuer prefixed did:chio: whose remainder is not exactly 64 lowercase hex characters. Raised for any artifact family, not only witnesses.Delegation Witnesses
swarm witness issuer public key invalid: {error}The issuer string, prefixed or bare, does not parse as an Ed25519 public key. Also raised for any family: witness_issuer_public_key is the shared parser.Delegation Witnesses
swarm authority canonical JSON failed: {detail}The other error variant. Its text comes from the Display on SwarmAuthorityError::Canonical in crates/kernel/chio-swarm-authority/src/error.rs, not from a verifier call site. Canonical JSON encoding or Ed25519 verification raised rather than returning false. It is a fault, not a policy refusal.Swarm Authority

Task graph structure

Denial stringProduced whenMechanism
unsupported swarm task graph schema: {schema}Schema tag is not chio.swarm.task-graph.v1.Task Graphs
swarm task graph is from the futurecreated_at_unix_ms is after the bundle’s now_unix_ms.Task Graphs
swarm task graph is expiredexpires_at_unix_ms is at or before now. Expiry is inclusive.Task Graphs
swarm task graph requires at least one taskEmpty nodes.Task Graphs
swarm task graph max_fanout must be positiveA zero ceiling would forbid every edge. max_depth has no equivalent floor.Task Graphs
swarm task graph requires exactly one root taskThe count of nodes with no parent and depth zero is not one.Task Graphs
swarm root-depth task has parent: {task_id}Depth zero with a parent_task_id.Task Graphs
swarm non-root task missing parent: {task_id}Depth above zero with no parent.Task Graphs
duplicate swarm task id: {task_id}Two nodes share an id. Raised while building the task index, before any edge is read.Task Graphs
unknown swarm edge source: {task_id}An edge names a task that is not in the graph. Raised from both edge validation and depth validation.Task Graphs
unknown swarm edge target: {task_id}Same, on the other end of the edge.Task Graphs
duplicate swarm task graph edgeThe deduplicated edge set is smaller than the edge list. Does not name the offender.Task Graphs
swarm task parent edge missing: {parent} -> {child}A node declares a parent with no corresponding edge. Parentage must be stated twice and agree.Task Graphs
swarm task depth mismatch: {from} -> {to}Child depth is not parent depth plus one. Exact arithmetic, not an inequality.Task Graphs
swarm task depth overflowParent depth plus one overflows the integer type.Task Graphs
swarm task exceeds max depth: {task_id}A node’s depth is above the signed max_depth. Fixture max-depth-exceeded.Task Graphs
swarm task exceeds max fanout: {task_id}Outgoing edge count from one task passes max_fanout. The id named is the parent.Task Graphs
swarm task graph cycle at {task_id}Depth-first walk re-enters a task still on the stack. Fixture graph-cycle.Task Graphs
swarm task graph issuer is not trusted: {graph_id}The graph’s issuer key parsed but is not in the pinned slice.Swarm Authority
swarm task graph signature invalid: {graph_id}Signature verified false over the graph body with signature removed. A trailing : {error} means the hex did not parse at all.Task Graphs
duplicate swarm join id: {join_id}Two joins declared in the graph share an id.Task Graphs
swarm join requires parents: {join_id}Empty parent_task_ids.Task Graphs
swarm join requires at least two parents: {join_id}Exactly one parent. A one-parent fan-in is an edge, and must be modeled as one.Task Graphs
swarm join next task is unknown: {next_task_id}The join targets a task that is not in the graph.Task Graphs
swarm join next task is a parent: {join_id}The join’s target also appears among its parents.Task Graphs
swarm join parent task is unknown: {parent_task_id}A declared parent is not in the graph.Task Graphs

Route-plan receipts

Denial stringProduced whenMechanism
unsupported swarm route-plan receipt schema: {schema}Schema tag is not the route-plan receipt tag.Route Plans
swarm route-plan egress constraints missing: {route_plan_id}Empty egress_constraints. At least one is required.Route Plans
unsupported swarm route-plan egress constraint: {constraint}Any entry other than the literal deny-private-network. The vocabulary is closed at one value. Fixture egress-constraint-unsupported.Route Plans
swarm route-plan selected route bridge mismatch: {route_plan_id}selected_route has no :, or its prefix is not bridge_id. Fixture route-plan-mismatch.Route Plans
swarm route-plan protocol target bridge mismatch: {route_plan_id}protocol_target does not start with {bridge_id}://.Route Plans
swarm route-plan egress contract bridge mismatch: {route_plan_id}egress_contract_id does not start with {bridge_id}:.Route Plans
swarm route-plan attenuation was not acceptedattenuation_decision is any string other than accepted. Does not name the receipt.Route Plans
swarm route-plan receipt is stale: {route_plan_id}Receipt expiry is at or before now. Fixture stale-route-plan.Route Plans
swarm route-plan issuer is not trusted: {route_plan_id}Parsed issuer key is not in the pinned slice.Swarm Authority
swarm route-plan signature invalid: {route_plan_id}Signature verified false, or with a trailing : {error}, the hex did not parse.Route Plans
swarm route-plan task is unknown: {task_id}The receipt is scoped to a task that is not in the graph.Route Plans
unknown swarm route-plan ref: {route_plan_id}A supplied receipt is not listed in the graph’s route_plan_refs.Route Plans
missing swarm route-plan receipt: {route_plan_ref}A declared ref has no receipt. The other half of the same totality check.Route Plans
duplicate swarm route-plan receipt: {route_plan_id}Two receipts share an id.Route Plans

Join receipts

Denial stringProduced whenMechanism
unsupported swarm join receipt schema: {schema}Schema tag is not the join receipt tag.Join & Terminal Receipts
swarm join receipt dag ordinal must be positive: {join_id}Ordinal is zero. Enforced both at mint and at verification.Join & Terminal Receipts
swarm join receipt is from the future: {join_id}hlc_unix_ms is after now. There is no upper bound on how old a join receipt may be.Join & Terminal Receipts
unknown swarm join receipt: {join_id}A receipt whose id matches no join declared in the graph.Join & Terminal Receipts
missing swarm join receipt: {join_id}A declared join has no receipt.Join & Terminal Receipts
duplicate swarm join receipt: {join_id}Two receipts share a join id.Join & Terminal Receipts
swarm join receipt next task mismatch: {join_id}The receipt’s next_task_id differs from the graph join’s.Join & Terminal Receipts
swarm join receipt next task is unknown: {next_task_id}That target is not a task in the graph.Join & Terminal Receipts
swarm join receipt parent count mismatch: {join_id}Expected-parent-receipt count differs from the graph join’s parent count.Join & Terminal Receipts
swarm join receipt predicate unsupported: {join_predicate}Predicate is not all_success, any_success, or quorum:N; or N does not parse, is zero, or exceeds the expected parent count. Three call sites share this string.Join & Terminal Receipts
swarm join receipt parent set mismatch: {join_id}Four call sites share this string: all_success with unequal expected and actual sets, any_success with zero actuals, quorum:N with fewer actuals than N, and an actual receipt id that is not in the expected set. Fixture join-parent-set-mismatch.Join & Terminal Receipts
swarm join receipt parent set hash mismatch: {join_id}The declared parent_set_hash differs from the recomputed digest over the chain id plus sorted actual receipt ids.Join & Terminal Receipts
swarm join receipt parent task receipts mismatch: {join_id}The per-parent receipt list does not correspond one to one with the expected-to-actual pairs, in count, membership, or sorted task and receipt ids. Three call sites share this string.Join & Terminal Receipts
swarm join receipt issuer is not trusted: {join_id}Parsed issuer key is not in the pinned slice.Swarm Authority
swarm join receipt signature invalid: {join_id}Signature verified false, or with a trailing : {error}, the hex did not parse.Join & Terminal Receipts

Budget pool and allocations

Denial stringProduced whenMechanism
unsupported swarm budget pool schema: {schema}Schema tag is not the budget pool tag.Sub-Agent Budgets
swarm budget pool ref mismatchThe pool’s id is not the graph’s budget_pool_ref. One graph, one pool.Sub-Agent Budgets
swarm budget allocation task is unknown: {task_id}An allocation is scoped to a task that is not in the graph.Sub-Agent Budgets
swarm budget allocation unit rollup mismatch: {allocation_id}Reserved plus active plus consumed plus released plus reversed does not equal max_units exactly.Sub-Agent Budgets
swarm budget allocation has no active units: {allocation_id}State is active with zero active units.Sub-Agent Budgets
swarm budget allocation is not active: {allocation_id}A continuation names an allocation in any state other than active. Raised during continuation validation, which is why a released allocation denies the child rather than the pool.Sub-Agent Budgets
duplicate swarm budget allocation: {allocation_id}Two allocations share an id.Sub-Agent Budgets
swarm budget allocations exceed pool totalSummed max_units is above total_units. Fixture budget-allocations-exceed-pool.Sub-Agent Budgets
swarm budget allocation overflowSumming allocations across the pool overflowed. Checked arithmetic throughout, never clamped.Sub-Agent Budgets
swarm budget allocation unit overflowSumming one allocation’s five state counts overflowed.Sub-Agent Budgets

Revocation epoch

Denial stringProduced whenMechanism
unsupported swarm revocation epoch schema: {schema}Schema tag is not the revocation epoch tag.Revocation Epochs
swarm revocation epoch ref mismatchThe epoch’s id is not the graph’s revocation_epoch_ref.Revocation Epochs
swarm revocation epoch is from the futureissued_at_unix_ms is after now.Revocation Epochs
swarm revocation epoch window is emptyvalid_until_unix_ms is at or before issued_at_unix_ms.Revocation Epochs
swarm revocation epoch is staleThe window closed at or before now. An expired epoch denies the whole bundle rather than degrading to no revocation.Revocation Epochs
swarm revocation epoch root mismatchThe declared root_hash differs from the digest recomputed over the sorted revoked-subject and revoked-task lists.Revocation Epochs
swarm revocation epoch issuer is not pinned: {epoch_id}Issuer key is not in the pinned slice. The wording differs from every other family, which says is not trusted. The comparison is also written inline in verify_revocation_epoch_signature rather than in an ensure_*_issuer_is_pinned helper, which is why it carries no empty-slice pre-check.Revocation Epochs
swarm revocation epoch signature invalid: {epoch_id}Signature verified false, or with a trailing : {error}, the hex did not parse.Revocation Epochs
swarm authority subject is revoked: {subject}The epoch names the graph issuer, the planner subject, or any witness hop issuer. Those three are the whole check: validate_revocation_epoch never tests the route-plan, join-receipt, continuation, or terminal-receipt issuers against revoked_subjects. Revoking one of those subjects does not deny a bundle it signed. Three call sites share the string.Revocation Epochs
swarm task is revoked: {task_id}A revoked task id is present in the graph. Fixture revoked-task.Revocation Epochs

Terminal graph receipts

Join & Terminal Receipts owns the artifact and the set-equality rule. Sub-Agent Budgets owns the rollup arithmetic these rows compare against, so the budget rows point there.

Denial stringProduced whenMechanism
missing swarm terminal graph receiptEmpty terminal_receipts. The field is serde(default), so an absent field and an empty list both land here.Join & Terminal Receipts
unsupported swarm terminal receipt schema: {schema}Schema tag is not the terminal graph receipt tag.Join & Terminal Receipts
duplicate swarm terminal receipt: {receipt_id}Two terminal receipts share an id.Join & Terminal Receipts
swarm terminal receipt is from the future: {receipt_id}completed_at_unix_ms is after now.Join & Terminal Receipts
swarm terminal budget pool mismatch: {receipt_id}The receipt names a different pool id than the bundle’s.Sub-Agent Budgets
swarm terminal revocation epoch mismatch: {receipt_id}The receipt names a different epoch id than the bundle’s.Revocation Epochs
swarm terminal task is unknown: {terminal_task_id}A terminal task id is not in the graph. This list only needs to reference known tasks, not cover them.Join & Terminal Receipts
swarm terminal completed task set mismatch: {receipt_id}Completed task ids are not exactly the graph’s task set. Set equality, so a receipt cannot close part of a graph.Join & Terminal Receipts
swarm terminal join receipt set mismatch: {receipt_id}Join receipt ids are not exactly the validated join set.Join & Terminal Receipts
swarm terminal route-plan set mismatch: {receipt_id}Route-plan receipt ids are not exactly the validated route set.Route Plans
duplicate swarm terminal budget rollup: {dimension_id}Two rollups share a dimension.Sub-Agent Budgets
swarm terminal budget rollup total mismatch: {dimension_id}One rollup’s five state counts do not sum to its own declared total_units.Sub-Agent Budgets
swarm terminal budget rollup mismatch: {receipt_id}The declared per-dimension map differs from the map recomputed over the pool’s validated allocations, every one of them whatever its state. Compared whole, so a missing dimension is the same failure as a wrong count.Sub-Agent Budgets
swarm terminal budget exceeds pool total: {receipt_id}Summed rollup totals are above total_units.Sub-Agent Budgets
swarm terminal budget rollup overflowAny rollup addition overflowed: one per unit column in add_allocation, one in total_units, and one folding the per-dimension totals. Seven call sites share this string.Sub-Agent Budgets
swarm terminal receipt issuer is not trusted: {receipt_id}Parsed issuer key is not in the pinned slice.Swarm Authority
swarm terminal receipt signature invalid: {receipt_id}Signature verified false, or with a trailing : {error}, the hex did not parse.Join & Terminal Receipts

Continuation tokens

This is the largest family, because a continuation is the artifact that binds all the others. Its rows point at whichever binding failed rather than at continuations generically.

Denial stringProduced whenMechanism
unsupported swarm continuation token schema: {schema}Schema tag is not the continuation token tag.Continuation Tokens
swarm continuation token is from the future: {token_id}issued_at_unix_ms is after now.Continuation Tokens
swarm continuation token is stale: {token_id}Expiry is at or before now. Fixture stale-continuation.Continuation Tokens
swarm continuation nonce replay: {token_id}Two tokens in one bundle share a nonce. Within-bundle only. Fixture replayed-continuation-nonce.Continuation Tokens
duplicate swarm continuation token: {token_id}Two tokens share an id.Continuation Tokens
swarm task continuation token ref missing: {task_id}A task with a parent names no continuation token.Continuation Tokens
missing swarm continuation token: {token_ref}A task names a token id that is not in the bundle. A second call site sits in the hop-report pass, which runs after the same check over a map with the same membership and therefore cannot fire.Continuation Tokens
swarm continuation token task mismatch: {token_ref}The named token exists but its child_task_id is a different task.Continuation Tokens
swarm continuation child task is unknown: {child_task_id}The token names a task that is not in the graph.Task Graphs
swarm continuation graph digest mismatch: {token_id}graph_sha256 differs from the canonical digest of the whole task graph, signature field included.Task Graphs
swarm continuation must choose parent task or join receipt: {token_id}Both parent_task_id and join_receipt_id are set.Continuation Tokens
swarm continuation missing parent context: {token_id}Neither is set.Continuation Tokens
swarm continuation parent task mismatch: {token_id}The token’s parent is not the child task’s declared parent.Task Graphs
swarm continuation parent edge mismatch: {token_id}No graph edge runs from that parent to that child.Task Graphs
swarm continuation lacks parent receipt: {token_id}A parent-task token carries an empty parent_receipt_ids.Continuation Tokens
swarm continuation join receipt is unknown: {join_receipt_id}A join token names a receipt that did not validate into the join index.Task Graphs
swarm continuation join target mismatch: {token_id}The join’s next_task_id is not the token’s child task.Task Graphs
swarm continuation join parent receipts mismatch: {token_id}The token’s parent receipt ids, sorted, differ from the join receipt’s actual parent receipt ids.Task Graphs
swarm continuation witness chain binding missing: {token_id}A parent-task token carries no witness_chain_ref. Also enforced at mint.Delegation Witnesses
swarm continuation witness chain digest missing: {token_id}A ref without its witness_chain_sha256.Delegation Witnesses
swarm continuation witness chain binding without parent task: {token_id}A join token carries a witness ref or digest. A fan-in is witnessed per edge, not per join.Delegation Witnesses
swarm continuation witness chain mismatch: {token_id}No chain with that id, or its parent and child tasks are not the token’s.Delegation Witnesses
swarm continuation witness chain digest mismatch: {token_id}The declared digest differs from the canonical digest of the referenced chain.Delegation Witnesses
swarm continuation route-plan ref missing: {token_id}The child task declares no route_plan_ref. Every continued task must be routed.Route Plans
swarm continuation route-plan ref mismatch: {token_id}The child task’s declared ref is not the token’s route_plan_receipt_id.Route Plans
swarm continuation route-plan receipt is unknown: {route_plan_receipt_id}The named receipt did not validate into the route index.Route Plans
swarm continuation route-plan task mismatch: {token_id}The receipt is scoped to a different task than the token’s child.Route Plans
swarm continuation budget ref missing: {token_id}The child task declares no budget_allocation_ref.Sub-Agent Budgets
swarm continuation budget ref mismatch: {token_id}That ref is not the token’s budget_allocation_id.Sub-Agent Budgets
swarm continuation budget allocation is unknown: {budget_allocation_id}The named allocation is not in the validated pool.Sub-Agent Budgets
swarm continuation budget task mismatch: {token_id}The allocation is scoped to a different task than the token’s child.Sub-Agent Budgets
swarm continuation revocation epoch mismatch: {token_id}The token names a different epoch id than the bundle’s.Revocation Epochs
swarm continuation revocation epoch root mismatch: {token_id}The token’s epoch root hash differs from the epoch’s. A token cannot be presented against an epoch it did not commit to.Revocation Epochs
swarm continuation issuer is not trusted: {token_id}Parsed issuer key is not in the pinned slice.Swarm Authority
swarm continuation signature invalid: {token_id}Signature verified false, or with a trailing : {error}, the hex did not parse.Continuation Tokens

Delegation witness chains

Denial stringProduced whenMechanism
unsupported swarm delegation witness chain schema: {schema}Schema tag is not the witness chain tag.Delegation Witnesses
missing swarm delegation witness chain: {parent} -> {child}A graph edge has no chain. Every edge must be covered.Delegation Witnesses
duplicate swarm delegation witness chain: {parent} -> {child}Two chains cover the same edge. Exactly once, not at least once.Delegation Witnesses
swarm witness chain edge mismatch: {chain_id}The chain’s parent and child pair is not an edge in the graph.Task Graphs
swarm witness chain parent task is unknown: {parent_task_id}The chain names a parent that is not in the graph.Task Graphs
swarm witness chain child task is unknown: {child_task_id}Same, for the child.Task Graphs
swarm witness chain has no hops: {chain_id}Empty hops.Delegation Witnesses
swarm witness parent scope mismatch: {chain_id}The first hop’s parent scope hash is not the parent task’s scope_hash.Delegation Witnesses
swarm witness child scope mismatch: {chain_id}The last hop’s child scope hash is not the child task’s. Fixture witness-child-scope-mismatch.Delegation Witnesses
swarm multi-hop witness chain feature gate missing: {chain_id}More than one hop while the signed graph does not set multiHopWitnessChains. A per-graph gate inside the signed artifact, not a verifier default.Delegation Witnesses
swarm witness hop scope discontinuity: {chain_id}One hop’s child scope hash is not the next hop’s parent scope hash.Delegation Witnesses
swarm witness hop capability discontinuity: {chain_id}Same break, in the capability digests.Delegation Witnesses
swarm witness hop is stale: {chain_id}A hop’s expiry is at or before now. Names the chain, not the hop.Delegation Witnesses
swarm attenuation witness invalid: {error}The scope-subset proof failed. The nested text comes from validate_attenuation_proof in chio-core-types and is capability vocabulary, not swarm vocabulary.Delegation Witnesses
swarm witness issuer is not trusted: {chain_id}A hop’s issuer key is not in the pinned slice.Swarm Authority
swarm witness signature invalid: {chain_id}A hop signature verified false, or with a trailing : {error}, the hex did not parse.Delegation Witnesses

Route metadata, runtime only

These eight messages have no counterpart on the proof paths. They come from verify_route_metadata_matches in chio-runtime-core, which compares the live route selection the kernel is about to take against the signed route-plan receipt. Every one arrives as chio_swarm_authority_rejected and every one belongs to Route Plans. The outer key is read as route, route_selection, or routeSelection. The three inner fields each take a list of alternates, spelled out in the table: the bridge accepts four names, two of which do not contain the word bridge at all, and the selected route accepts four. First match wins; the rest are not consulted.

On acceptance the hook does not store what it read. It stores its own normalized { route: { bridge, protocolTarget, selectedRoute } } under verified_swarm_route_metadata, and dispatch revalidation compares against that, not against whatever alternate spellings the original request used.

Denial stringProduced when
swarm route metadata missing for route plan {route_plan_id}No metadata was passed with the request at all.
swarm route metadata missing routed entry for route plan {route_plan_id}Metadata carries none of the three route keys.
swarm route metadata missing bridge for route plan {route_plan_id}No bridge, bridgeId, targetProtocol, or selectedTargetProtocol string.
swarm route metadata bridge mismatch: expected {expected}, got {actual}The live bridge is not the receipt’s bridge_id.
swarm route metadata missing protocol target for route plan {route_plan_id}No protocolTarget or protocol_target string.
swarm route metadata target mismatch: expected {expected}, got {actual}The live target is not the receipt’s.
swarm route metadata missing selected route for route plan {route_plan_id}No selectedRoute, selected_route, selectedRouteId, or selected_route_id string.
swarm route metadata selected route mismatch: expected {expected}, got {actual}The live route is not the receipt’s.

Constructor messages, not a runtime path

The crate’s mint_*, sign_*, and budget fan-out and fan-in helpers also return Rejected. Their callers in the workspace are the crate’s tests and its examples/agent_os.rs binary, so these strings appear in a test failure or an example run rather than a denial. The two mint_* helpers and the two budget fan-out and fan-in helpers are the test-only ones; every sign_* helper is also called by the example. Two shapes are formulaic across seven families, where {family} is one of task graph, continuation, join receipt, route-plan, revocation epoch, terminal receipt, and witness: swarm {family} issuer public key invalid: {detail} and swarm {family} signer does not match issuer: {id}. The witness member of the first pair collides with the verification-path message of the same wording, so swarm witness issuer public key invalid does not tell you which side produced it; every other family’s version of that string is constructor-only. The remainder are swarm continuation expiry must be after issue time: {token_id}, swarm join receipt parent task receipts missing: {join_id}, swarm join receipt actual parent receipts missing: {join_id}, swarm budget fanout allocations missing, swarm budget fanout allocation units missing: {allocation_id}, swarm budget fanout overflow, swarm budget fanout exceeds pool total, swarm budget fanin completed tasks missing, swarm budget fanin release overflow, swarm budget fanin release exceeds allocation: {allocation_id}, and swarm budget fanin task has no allocation.


Guarantees and limits

StatusClaimEvidence
ShippedEvery failure listed here is fail-closed. There is no warning state, no partial verdict, and no per-artifact error list: the first refusal returns and no report exists.verify_swarm_authority_bundle is a straight sequence of ? calls
ShippedThe verifier itself does run in a shipped binary, just not on the admission path. chio proof verify and the proof room both call verify_swarm_authority_bundle directly, with keys read from CHIO_SWARM_TRUSTED_WITNESS_KEYS and the clock read at verification.chio-cli/src/cli/dispatch/proof.rs; chio-proof-room/src/source_verifier.rs
ShippedReplay denial agrees across all three admission-store backends, and only for single_use tokens. A resumable token is never consumed and never replay-denied.store/memory.rs, store/json.rs, store/sqlite/admission_replay.rs; SwarmContinuationMode in swarm_authority.rs
Proved by testAn admitted single-use token denies on second presentation with chio_swarm_continuation_replay, in memory and on SQLite, while dispatch revalidation of the first admission still passes.chio_runtime_hook_revalidates_reserved_swarm_continuation_then_denies_replay, sqlite_runtime_hook_denies_replayed_swarm_continuation_before_dispatch
Proved by testA consume that errors or panics denies with swarm_continuation_consume_error, releases the treaty reservation, does not release the swarm one, and leaves the id burned.swarm_consume_error_releases_treaty_and_preserves_same_admission_swarm_marker and its panic twin
Proved by fixture replay11 verifier messages are pinned as negative slugs and replayed on every chio proof doctor --scenario proof-package. A reworded message fails the fixture rather than passing silently.fixtures/proof-room/swarm-authority/negatives/*.json; the negative-transaction-passport entries in fixtures/proof-room/catalog.json; check_transaction_passport_rejects
Proved by testA minority of the written-out messages have an assertion behind them, nearly all by substring in the verifier’s own test suite, plus swarm task graph is expired from the CLI and proof-room tests and swarm task exceeds max depth from the max-depth-exceeded fixture. The fixtures in SWARM_AUTHORITY_CHECKS are additionally replayed under --scenario swarm-authority against a literal substring.crates/kernel/chio-swarm-authority/tests/swarm_authority_stage0.rs; SWARM_AUTHORITY_CHECKS in chio-cli/src/cli/dispatch/proof/doctor.rs
LimitThe rest of the messages, including every one generated from a field label, have no regression protection. Nothing asserts their text, so treat any match on them as a heuristic that can break in a patch release.No label template appears in any assertion; grep a template string to confirm
LimitMessages are not unique to a call site. swarm terminal budget rollup overflow and the empty-key-slice message have seven producers each, swarm join receipt parent set mismatch four, and swarm authority subject is revoked, swarm join receipt parent task receipts mismatch, swarm join receipt predicate unsupported, and swarm witness chain has no hops three each. Ten more have two, including both edge-source and edge-target unknowns and all three route-plan bridge mismatches. The string identifies a rule, not a line.Call-site extraction over verifier.rs, verifier/witness.rs, and verifier/budget_accounting.rs: rejected() call sites outnumber the distinct format strings they pass
LimitSeveral refusals do not name the offender: duplicate swarm task graph edge, swarm budget pool ref mismatch, swarm revocation epoch ref mismatch, swarm revocation epoch root mismatch, swarm route-plan attenuation was not accepted, the three epoch time checks, and the whole overflow family. Expect to diff the bundle by hand.verifier.rs
LimitAn unknown JSON key never produces any of the strings catalogued here. Every artifact struct carries serde(deny_unknown_fields), so a stray key fails deserialization before the verifier runs, and the operator sees a serde message such as unknown field from whichever loader was reading.crates/kernel/chio-swarm-authority/src/types.rs
LimitA bundle only verifies once the graph is finished. terminal_receipts must be non-empty and each receipt’s completed_task_ids must equal the graph’s whole task set, so there is no shape of bundle that verifies mid-flight with tasks still open.validate_terminal_graph_receipts, validate_terminal_graph_receipt_refs
LimitCycle detection is recursive and runs before the depth ceiling. validate_task_graph calls validate_roots at verifier.rs:585, then validate_acyclic, which recurses through visit_task, at verifier.rs:589; validate_edge_depths follows at verifier.rs:590 and validate_graph_limits, which enforces max_depth, at verifier.rs:591. A graph with a very long chain walks the native stack before any ceiling applies.visit_task, validate_task_graph
Not claimedStable machine-readable error codes out of the verifier crate. SwarmAuthorityError is two variants over strings. Callers map the whole error to one code or one slug.crates/kernel/chio-swarm-authority/src/error.rs
Not claimedThat CHIO_RUNTIME_FAILURE_CODES is exhaustive. It is a declared registry read by one test, not consulted on any denial path, and at least one emitted store code is absent from it.runtime_failure_code_registry_covers_hook_surface_codes; duplicate_swarm_authority_bundle in store/json.rs
Shipped, not wiredThe runtime codes are reachable only from an embedder that calls with_swarm_witness_keys and populates the admission store. Both are public on the chio-runtime facade, and no product binary calls either. Because the bundle lookup runs first, a swarm-bound request against an unpopulated store denies with missing_chio_swarm_authority_bundle; the empty-key-slice message is only reachable once a bundle is stored.Call sites of with_swarm_witness_keys and insert_swarm_authority_bundle; crates/kernel/chio-runtime/src/stores.rs
UnsupportedRecovering the verifier sentence from a denial receipt. The hook keeps the code and discards the detail, and the metadata has no field for it. The proof paths are the only place to read the sentence, aside from a revalidation failure between admission and dispatch.runtime_denial_metadata; the { code, .. } destructure in admission_hook.rs

Next steps

  • Swarm Authority · the verifier that produces every message above, and the order it reads a bundle in
  • Continuation Tokens · the replay codes in context: reserve, consume, release, and the resumable exemption
  • Task Graphs · depth arithmetic, the single root, and the ceilings behind a third of these strings
  • Delegation Witnesses · edge cover, hop continuity, and the attenuation proof whose errors are nested inside one message
  • Route Plans · the bridge prefix rules and the live-metadata comparison that has no proof-path equivalent
  • Join & Terminal Receipts · the fan-in parent set and the closing receipt behind two of the tables above
  • Sub-Agent Budgets · allocation states, rollup arithmetic, and the terminal receipt that reconciles them
  • Revocation Epochs · the signed block-list every continuation commits to by root hash
  • Proof Room · where the negative fixtures live, and the path that prints the sentence rather than the code