Validation states
Every result from verify falls into one of four states. Each element is { manifest, binding }; the signed states are carried on result.manifest.validation_state, typed ValidationState = "Invalid" | "Valid" | "Trusted"; the unsigned state is an empty array.
The four states
The three signed states map directly to the C2PA 2.3 §15 validation outcomes. The split is deliberate: a viewer can tell whether bytes were tampered (Invalid) apart from whether the publisher is one the application has chosen to recognize (Valid vs Trusted). Conflating the two is the most common mistake in provenance UIs, and it renders badges meaningless.
| State | result | Signature intact? | Chain reaches anchor? | Cause | UI treatment |
|---|---|---|---|---|---|
| Unsigned | empty array | n/a | n/a | Content predates signing, nothing recovered | Render plain content, no badge |
| Trusted | manifest.active_manifest set | yes | yes | Spec's terminal success state | Green badge |
| Valid | manifest.active_manifest set | yes | no | Legitimate signer in neither your anchor list nor the (default-on) C2PA conformance list, or impersonator | "Signed but unverified issuer" (permissive), or treat as failure (strict) |
| Invalid | manifest.active_manifest set | no | n/a | Bytes modified after signing or signature did not verify | Surface loudly |
The difference between Valid and Trusted is the anchor set: your trust anchor list plus, by default, the bundled C2PA conformance trust list. A Valid manifest has an intact signature whose chain reaches neither. Pass trustC2paAnchors: false to make your list the only deciding set.
Do not render "not signed" warnings on most content; users quickly learn to ignore warnings that appear everywhere, which defeats the badge on content that genuinely needs one.
Failure modes
verify throws an SdkError when the bytes cannot be parsed (corrupted file, truncated download), when the registry is unreachable, or when a recovered manifest fails validation. Catch the error and show a generic "could not verify" state. An unsigned asset is not an error; it's an empty array.
When a result's manifest.active_manifest is set but result.manifest.validation_results?.activeManifest?.failure contains entries, the file was tampered. Log a failure entry for diagnostics and show the user a single "modified after signing" message.
See also
- Trust anchors: what separates
ValidfromTrusted. - Verify an asset: read
validation_stateoff a result'smanifest.