Skip to main content

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):

CodeValueMeaning
InitInvalid0A media segment arrived before any valid init manifest was processed for the session.
ManifestInvalid1The init manifest itself failed validation.
SegmentHashMismatch3Segment content differs from the signed hash (tampering).
SegmentSignatureInvalid4The segment's signature failed its cryptographic check (tampering).
SegmentStructureInvalid5The segment is malformed at the container level.
SessionKeyExpired6The signing session key passed its validity period.
SessionKeyUnknown7The segment was signed with a key the verifier has not seen in any init manifest.
SigningCredentialExpired8The 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 stringMeaningSeverityUI treatment
livestream.segment.hash_mismatchSegment content differs from signed hashHigh (tampering)Surface tampered state immediately
livestream.segment.signature_invalidSignature on segment failed cryptographic checkHigh (tampering)Surface tampered state
livestream.signer.expiredSigner certificate authorizing the session key lapsed mid-sessionHigh (credential failure)Surface tampered/untrusted state
livestream.segment.structure_invalidSegment is malformed at the container levelMediumGeneric playback error
livestream.init.invalidMedia segment arrived before any init manifest was processedLow (timing)Wait for the next init
livestream.sessionkey.expiredActive session key passed its validityPeriodLow (transient)Wait for next init manifest, no UI noise
livestream.sessionkey.unknownSegment signed with a key the verifier does not recognizeLow (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 the init result; the session itself is untrustworthy. Do not show the badge for this session.
tip

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:

reasonMeaning
READER_INVALIDThe bytes could not be read or parsed.
TRUST_CONFIG_INVALIDThe 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