pub enum AphError {
Show 24 variants
InvalidEnvelopeSignature,
InvalidFlowTransition {
from: String,
to: String,
},
MandateExpired {
mandate_id: String,
},
RoleViolation {
role: String,
operation: String,
},
ChannelNotAllowed {
channel: String,
},
NotarySignatureInvalid,
HumanAuthenticationRequired,
NotaryServiceUnreachable,
EnvelopeBodyHashMismatch {
expected: String,
actual: String,
},
UnsupportedAlgorithm {
alg: String,
},
PrincipalSignatureInvalid,
AttestationModeRefused {
required: String,
actual: String,
},
ProofChainInvalid {
reason: String,
},
NotaryKeyNotPublished {
surface: String,
},
MandateRevoked {
mandate_id: String,
},
MandateRequired {
agent_did: String,
channel_kind: String,
},
AudienceMismatch {
audience_id: String,
verifier_id: String,
},
EnvelopeAlreadySpent {
envelope_id: String,
},
EnvelopeWindowInvalid {
valid_from: String,
valid_until: String,
observed_at: String,
},
RecipientClassNotAllowed {
declared: String,
mandate_id: String,
allowed: String,
},
SealUnopenable {
envelope_id: String,
},
SealSuiteUnknown {
suite: String,
supported: String,
},
SealReaderKeyUnpublished {
reader_id: String,
kid: String,
},
RotationAttestationInvalid {
reason: String,
},
}Expand description
APH protocol error with structured codes and suggestions.
Variants§
InvalidEnvelopeSignature
APH_E001 — the envelope’s proof.proofValue did not verify against
the notary’s public key over the canonical form.
InvalidFlowTransition
APH_E002 — a notarization flow was driven along an edge the state
machine does not define.
MandateExpired
APH_E003 — the referenced mandate is outside its validity window.
RoleViolation
APH_E004 — a party attempted an operation its role does not permit
under the §5 permission matrix.
Fields
ChannelNotAllowed
APH_E005 — the channel is not listed in the delegation mandate’s
allowedChannels.
NotarySignatureInvalid
APH_E006 — a mandate’s notarySignature did not verify (distinct
from APH_E001, which covers the envelope-level proof).
HumanAuthenticationRequired
APH_E007 — the operation requires a human decision that has not
been obtained.
NotaryServiceUnreachable
APH_E008 — a protocol-mandated fetch from a notary-hosted surface
did not succeed, so no decision could be made either way: the service
itself could not be reached, or a document it is contracted to serve
could not be reached, parsed, or validated — a DID Document (spec
§8.4.4) or a revocation status list credential (spec §6.3.3.4 case 2,
which folds TLS, parse, proof, issuer, purpose and freshness failures
into this one code because the verifier’s action and the operator’s
remedy are identical in all of them; log the specific cause, do not
mint a code for it). Distinct from APH_E014, which means the
surface ANSWERED and published nothing.
EnvelopeBodyHashMismatch
APH_E009 — the delivered body does not hash to the value the
envelope attests, indicating tampering or a mismatched payload.
Fields
UnsupportedAlgorithm
APH_E010 — the declared algorithm is outside the allow-list
(ES256, EdDSA); alg: none is always rejected here.
PrincipalSignatureInvalid
APH_E011 — a signature made by the HUMAN’s key did not verify:
the principal proof of a chain, or an embedded delegation mandate’s
principalSignature. Deliberately distinct from APH_E001 and
APH_E006, which are both NOTARY signatures — conflating them would
report a forged authorization as a notary misconfiguration.
AttestationModeRefused
APH_E012 — the verifier requires PrincipalSigned and the envelope
is NotaryAttested. Not a defect in the envelope: a refusal to accept
the weaker claim, which the spec forbids doing silently.
Fields
ProofChainInvalid
APH_E013 — the proof chain is malformed: wrong length, wrong
proofPurpose for a position, or a previousProof that is missing,
dangling, duplicated, or cyclic.
NotaryKeyNotPublished
APH_E014 — no notary key is published at the queried discovery
surface: the DNS TXT name carries no APH record (or none matching the
named kid), or a fetched DID Document names no key under the queried
fragment. Deliberately distinct from APH_E008, which means the
surface could not be REACHED: §8.4.6’s no-downgrade rule turns on
exactly this distinction — absence advances the fallback sequence,
failure must stop it — and a taxonomy that flattens the two forces
every consumer’s error surface to flatten them again.
MandateRevoked
APH_E015 — the parent delegation mandate’s bit is SET in the
revocation status list its issuing notary publishes (spec §6.3.3):
the human withdrew the standing authority this envelope was issued
under. The signatures are still valid — this is a WITHDRAWN
authorization, not a forged one, so reporting it as a signature
failure would send an operator to inspect key material when the
answer is a human decision. Deliberately distinct from APH_E003,
which is authority that ran out on schedule rather than authority
that was pulled.
Carries the mandate id alone, mirroring APH_E003: the revocation
timestamp lives in the notary’s status state, not in the refusal.
MandateRequired
APH_E016 — a human-not-present notarization (§9.2) was attempted with
no matching, unexpired delegation mandate: nothing authorized this act.
Held distinct from THREE neighbours because the remedies differ
completely — APH_E007 is nobody was asked (reach the human),
APH_E011 is the authorization presented is invalid (inspect it),
APH_E015 is the authorization was withdrawn (obtain a new one).
Reporting an ABSENT mandate under any of those conflates absence with
failure — the distinction this crate makes structural everywhere else
(discovery::DiscoveryOutcome). Added 2026-08-23 from an implementer
field report: the first production consumer had to misuse an
invalid-mandate code for exactly this case.
Fields
AudienceMismatch
APH_E017 — the envelope names an audience that is not this verifier:
its audience.id differs from the verifier’s own identity, or a
present channelBinding member differs from the delivery coordinates
of the act being performed.
REGISTERED AHEAD OF ITS RFC. The audience field is RFC 0003 (Draft)
and no type in this crate carries it yet — the code exists now, per the
specification’s additive-codes rule, so an implementation exercising
the draft ahead of ratification emits a stable code instead of minting
a private one. That is the same reasoning that added APH_E016 from a
field report: the first consumer to need a code should not have to
misuse a neighbour. An envelope with no audience member never
produces this code — absence is the producer’s decision to issue a
bearer credential, and RFC 0003 is explicit that a verifier that cannot
determine its OWN identity rejects rather than skips.
Fields
EnvelopeAlreadySpent
APH_E018 — this envelope was already accepted once. RFC 0003’s
single-use step: a verifier records id at the moment it commits to
the act (acceptance in the RFC 5321 §6.1 sense) and refuses every
later presentation of the same id. The record is the RECIPIENT’S
ledger obligation — two independent verifiers each accept once, which
is why audience binding (APH_E017) and single-use are load-bearing
together and neither is sufficient alone.
EnvelopeWindowInvalid
APH_E019 — the envelope’s OWN validity window fails against the
verifier’s clock: validFrom is in the future or validUntil is in
the past. Deliberately distinct from APH_E003, which is a mandate
consulted past its expiry; before this code existed an implementer
refusing an expired envelope had to invent a refusal or miscite
APH_E003, and this crate’s own tests nearly did.
Fields
RecipientClassNotAllowed
APH_E020 — the mandate constrains WHO may consume (RFC 0005’s
allowedRecipientClasses) and this envelope either declares a class
outside the grant or declares none at all. The second half is
deliberate: a constraint the envelope lets nobody check would be
escapable by omission, and the threat here is one’s own
honest-but-over-broad agent — exactly the party the refusal teaches.
Deliberately distinct from APH_E005, which is the MEDIUM being out
of scope; this is the CONSUMER being out of scope on an allowed
medium.
Fields
SealUnopenable
APH_E021 — a sealed payload addressed to THIS verifier did not
open: wrong key, tampered ciphertext, or a seal staged under a
different context (envelope, reader, or suite relabeled) — the four
cases AEAD makes indistinguishable by design. Per RFC 0008 §4 this
refuses the ENVELOPE, never the seal alone: an unopenable seal
addressed to you is evidence, not an inconvenience.
DECLARED BY spec/aph-0.2.md, absent from v0.1.0’s closed
twenty; emitted only on wires that declare sealedPayload.
SealSuiteUnknown
APH_E022 — the sealed payload names a ciphersuite this verifier
does not compile. One suite per draft, no negotiation; refused by
name before any key material is touched. Declared by
spec/aph-0.2.md.
Fields
SealReaderKeyUnpublished
APH_E023 — the seal’s reader key could not be discovered: the
reader’s DID document publishes no matching keyAgreement entry for
the named kid. Held distinct from APH_E014 exactly as E014 is
held distinct from E008: WHICH surface came up empty is the repair.
Declared by spec/aph-0.2.md.
Fields
RotationAttestationInvalid
APH_E024 — a rotation attestation (RFC 0001, v0.2) failed a
structural rule or its predecessor signature. The message carries the
SPECIFIC defect — which rule, which value — because “invalid” with no
reason teaches an operator nothing about a statement whose entire job
is auditability.
Implementations§
Source§impl AphError
impl AphError
Sourcepub fn suggestion(&self) -> &'static str
pub fn suggestion(&self) -> &'static str
Returns a human-readable suggestion for resolving this error.
Sourcepub fn invalid_flow_transition(
from: impl Into<String>,
to: impl Into<String>,
) -> Self
pub fn invalid_flow_transition( from: impl Into<String>, to: impl Into<String>, ) -> Self
Builds an APH_E002 naming the illegal edge that was attempted.
Sourcepub fn mandate_expired(mandate_id: impl Into<String>) -> Self
pub fn mandate_expired(mandate_id: impl Into<String>) -> Self
Builds an APH_E003 naming the expired mandate.
Sourcepub fn notary_key_not_published(surface: impl Into<String>) -> Self
pub fn notary_key_not_published(surface: impl Into<String>) -> Self
Builds an APH_E014 naming the surface that published nothing.
Sourcepub fn role_violation(
role: impl Into<String>,
operation: impl Into<String>,
) -> Self
pub fn role_violation( role: impl Into<String>, operation: impl Into<String>, ) -> Self
Builds an APH_E004 naming the role and the denied operation.
Sourcepub fn channel_not_allowed(channel: impl Into<String>) -> Self
pub fn channel_not_allowed(channel: impl Into<String>) -> Self
Builds an APH_E005 naming the out-of-scope channel.
Sourcepub fn envelope_body_hash_mismatch(
expected: impl Into<String>,
actual: impl Into<String>,
) -> Self
pub fn envelope_body_hash_mismatch( expected: impl Into<String>, actual: impl Into<String>, ) -> Self
Builds an APH_E009 carrying both the attested and the recomputed
hash so an investigator can tell which side diverged.
Sourcepub fn unsupported_algorithm(alg: impl Into<String>) -> Self
pub fn unsupported_algorithm(alg: impl Into<String>) -> Self
Builds an APH_E010 naming the rejected algorithm.
Sourcepub fn attestation_mode_refused(
required: impl Into<String>,
actual: impl Into<String>,
) -> Self
pub fn attestation_mode_refused( required: impl Into<String>, actual: impl Into<String>, ) -> Self
Builds an APH_E012 recording both modes, so an operator can see what
was demanded and what arrived without re-parsing the envelope.
Sourcepub fn proof_chain_invalid(reason: impl Into<String>) -> Self
pub fn proof_chain_invalid(reason: impl Into<String>) -> Self
Builds an APH_E013 naming what is wrong with the chain.
Sourcepub fn mandate_revoked(mandate_id: impl Into<String>) -> Self
pub fn mandate_revoked(mandate_id: impl Into<String>) -> Self
Builds an APH_E015 naming the revoked delegation mandate.
Sourcepub fn mandate_required(
agent_did: impl Into<String>,
channel_kind: impl Into<String>,
) -> Self
pub fn mandate_required( agent_did: impl Into<String>, channel_kind: impl Into<String>, ) -> Self
Builds an APH_E016 naming the agent and channel nothing authorized,
so the operator’s first question — WHO tried WHAT — is answered by the
error itself rather than by log correlation.
Sourcepub fn audience_mismatch(
audience_id: impl Into<String>,
verifier_id: impl Into<String>,
) -> Self
pub fn audience_mismatch( audience_id: impl Into<String>, verifier_id: impl Into<String>, ) -> Self
Builds an APH_E017 naming both identities, so the operator’s first
question — for WHOM was this envelope, and who am I — is answered by
the error itself.
Sourcepub fn envelope_already_spent(envelope_id: impl Into<String>) -> Self
pub fn envelope_already_spent(envelope_id: impl Into<String>) -> Self
Builds an APH_E018 naming the id whose second presentation was
refused, so an operator can find the first acceptance in their ledger.
Sourcepub fn envelope_window_invalid(
valid_from: impl Into<String>,
valid_until: impl Into<String>,
observed_at: impl Into<String>,
) -> Self
pub fn envelope_window_invalid( valid_from: impl Into<String>, valid_until: impl Into<String>, observed_at: impl Into<String>, ) -> Self
Builds an APH_E019 carrying the window verbatim and the instant it
was judged at; without all three, “expired” is unactionable.
Sourcepub fn recipient_class_not_allowed(
declared: impl Into<String>,
mandate_id: impl Into<String>,
allowed: impl Into<String>,
) -> Self
pub fn recipient_class_not_allowed( declared: impl Into<String>, mandate_id: impl Into<String>, allowed: impl Into<String>, ) -> Self
Builds an APH_E020 naming what was declared (or nothing), which
mandate constrained it, and what that mandate allows.
Sourcepub fn seal_unopenable(envelope_id: impl Into<String>) -> Self
pub fn seal_unopenable(envelope_id: impl Into<String>) -> Self
Builds an APH_E021 naming the envelope whose seal refused.
Sourcepub fn seal_suite_unknown(
suite: impl Into<String>,
supported: impl Into<String>,
) -> Self
pub fn seal_suite_unknown( suite: impl Into<String>, supported: impl Into<String>, ) -> Self
Builds an APH_E022 naming both the claimed and the supported suite.
Sourcepub fn seal_reader_key_unpublished(
reader_id: impl Into<String>,
kid: impl Into<String>,
) -> Self
pub fn seal_reader_key_unpublished( reader_id: impl Into<String>, kid: impl Into<String>, ) -> Self
Builds an APH_E023 naming the reader and the missing kid.
Sourcepub fn rotation_attestation_invalid(reason: impl Into<String>) -> Self
pub fn rotation_attestation_invalid(reason: impl Into<String>) -> Self
Builds an APH_E024 carrying the specific rule that refused.
Trait Implementations§
impl Eq for AphError
Source§impl Error for AphError
impl Error for AphError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()