Failure codes
Stream validation reports problems two ways: per-segment codes attached to a result (the segment was processed but something is off), and thrown errors when validation cannot proceed at all. This page covers both.
Per-segment codes
InitValidation and MediaValidation carry a codes array. Each entry is a ValidationCode:
interface ValidationCode {
code: string;
kind: 'success' | 'informational' | 'failure';
}
kind lets you triage without parsing code: success confirms a check passed, informational is benign context, failure is the only kind that should ever change what a viewer sees. A media result with valid: false always carries at least one failure code.
The failure code enum
Each failure code maps to a ValidationFailureCode (numeric values shown):
| Code | Value | Meaning |
|---|---|---|
InitInvalid | 0 | A media segment arrived before any valid init manifest was processed for the session. |
ManifestInvalid | 1 | The init manifest itself failed validation. |
SegmentHashMismatch | 3 | Segment content differs from the signed hash (tampering). |
SegmentSignatureInvalid | 4 | The segment's signature failed its cryptographic check (tampering). |
SegmentStructureInvalid | 5 | The segment is malformed at the container level. |
SessionKeyExpired | 6 | The signing session key passed its validity period. |
SessionKeyUnknown | 7 | The segment was signed with a key the verifier has not seen in any init manifest. |
SigningCredentialExpired | 8 | The certificate that authorized the current session key lapsed mid-session (a credential failure, distinct from SessionKeyExpired's benign rotation gap). |
Common codes and UI treatment
| Code string | Meaning | Severity | UI treatment |
|---|---|---|---|
livestream.segment.hash_mismatch | Segment content differs from signed hash | High (tampering) | Surface tampered state immediately |
livestream.segment.signature_invalid | Signature on segment failed cryptographic check | High (tampering) | Surface tampered state |
livestream.signer.expired | Signer certificate authorizing the session key lapsed mid-session | High (credential failure) | Surface tampered/untrusted state |
livestream.segment.structure_invalid | Segment is malformed at the container level | Medium | Generic playback error |
livestream.init.invalid | Media segment arrived before any init manifest was processed | Low (timing) | Wait for the next init |
livestream.sessionkey.expired | Active session key passed its validityPeriod | Low (transient) | Wait for next init manifest, no UI noise |
livestream.sessionkey.unknown | Segment signed with a key the verifier does not recognize | Low (rotation gap) | Wait for next init manifest, no UI noise |
Surfacing codes to viewers
- Tampering (
SegmentHashMismatch,SegmentSignatureInvalid,SigningCredentialExpired): the content does not match what was signed, or the credential that signed it is no longer valid. Drop the verified badge and surface a tampered state immediately. - Timing and rotation (
InitInvalid,SessionKeyExpired,SessionKeyUnknown): transient gaps that resolve when the next init manifest lands. Hold the prior state quietly; do not flash a warning. - Structure (
SegmentStructureInvalid): a malformed container is a playback problem, not a provenance verdict. Show a generic playback error. - Manifest (
ManifestInvalid): appears on theinitresult; the session itself is untrustworthy. Do not show the badge for this session.
Surface tampered loudly, surface "could not verify yet" quietly. A banner that flickers on every key rotation quickly loses meaning for viewers.
Thrown errors
A genuine failure (bad bytes, misconfigured trust, a broken stream) rejects the validate promise with an SdkError — the same shape the issuer SDK throws — rather than returning codes. It's a discriminated union on kind:
type SdkError =
| { kind: "reason"; code: Code; message: string; reason: string; domain: string; metadata: Record<string, string> }
| { kind: "invalid"; code: Code; message: string; fieldViolations: FieldViolation[] }
| { kind: "status"; code: Code; message: string };
code (a coarse class, e.g. "not_found") and message are on every shape. switch on err.kind; a semantic error (kind: "reason") carries the stable machine-readable reason you branch on:
reason | Meaning |
|---|---|
READER_INVALID | The bytes could not be read or parsed. |
TRUST_CONFIG_INVALID | The trust anchors are missing or invalid. |
STREAM_INVALID, STREAM_LEDGER, LIVESTREAM_* | A stream-level processing error — the LIVESTREAM_* reason names the precise cause (e.g. LIVESTREAM_SESSIONKEY_EXPIRED). |
A per-segment failure code means this segment is bad; a thrown SdkError means the call could not run. Handle them separately.
See also
- Verify a live stream: where
codesappear on the result union. - Validation states: the
Invalid/Valid/Trustedbadge states.