Errors
Every error thrown by the SDK extends OpenACError, which carries a stable code: ErrorCode plus a human-readable message. The runtime classes group codes by phase:
import {
OpenACError,
SetupError,
ProofError,
VerificationError,
InputError,
WasmError,
} from "openac-sdk";
try {
await openac.precompute(req);
} catch (err) {
if (err instanceof InputError && err.code === "INVALID_JWT") {
// ...recover or surface to the user
}
throw err;
}
Source: src/errors.ts. The ErrorCode union is exported from src/types.ts.
Code reference
| Code | Class | Thrown when | Remediation |
|---|---|---|---|
SETUP_FAILED | SetupError | OpenAC.init failed to initialize the WASM bridge or witness calculator. | Verify the WASM build artifacts exist and assetsDir resolves; re-run npm run build:wasm. |
SETUP_NOT_SUPPORTED | WasmError | A code path tried to invoke setup inside WASM. Setup is offline-only (Rust CLI). | Use NativeBackend.setup or pre-generate keys. |
KEYS_NOT_FOUND | SetupError | NativeBackend could not locate the ecdsa-spartan2 binary or Cargo.toml. | Pass an explicit binaryPath / workDir, or build with cargo build --release. |
KEY_LOAD_FAILED | WasmError | loadKeysFromUrl got a non-200 response, or NativeBackend.loadArtifact failed. | Check the CDN URL and VcSize; verify network access and CORS. |
PROOF_GENERATION_FAILED | ProofError | The Spartan2 prover threw, or a CLI command exited non-zero. Includes cause. | Re-run with RUST_LOG=debug (Native) or inspect the WASM console; usually indicates malformed inputs or a key/circuit mismatch. |
WITNESS_GENERATION_FAILED | ProofError | The Circom-generated witness calculator threw on the supplied inputs. | Compare your inputs against tests/e2e.test.ts; typical causes are out-of-range claim values or wrong jwtParams. |
REBLIND_FAILED | ProofError | The present WASM call rejected the (instance, witness) pair before reblinding. | Check that precomputed was generated by the same KeySet; do not mutate the witness between precompute and present. |
VERIFICATION_FAILED | VerificationError | Verifier returned valid = false for a non-format reason (signature, commitment, or predicate output mismatch). | Inspect result.error; verify the verifier nonce was bound to the same Show witness. |
INVALID_PROOF_FORMAT | VerificationError | The serialized proof could not be parsed (wrong length / version). | Confirm both sides use the same SDK version; re-issue the bundle. |
COMMITMENT_MISMATCH | VerificationError | The linking commitment between Prepare and Show did not match. | The proofs were not built from the same precomputation; regenerate Show from the cached PrecomputedCredential. |
INVALID_JWT | InputError | The compact JWT could not be parsed, the header is not ES256, or the issuer signature did not verify locally. | Validate the JWT with an off-the-shelf SD-JWT parser; ensure issuerPublicKey matches the issuer. |
INVALID_KEY | InputError | A JWK was passed without kty: "EC" and crv: "P-256", or the device key was malformed. | Use a P-256 JWK; for PEM keys, wrap them as { pem: "..." }. |
INVALID_SIGNATURE | InputError | buildShowCircuitInputs could not verify the device-nonce signature against the device key in the credential. | Make sure devicePrivateKey corresponds to the credential's cnf.jwk. |
MISSING_DISCLOSURE | InputError | The credential references an _sd digest with no matching disclosure. | Include all disclosures the verifier expects; an SD-JWT issuer must publish disclosures together with the JWT. |
BIRTHDAY_NOT_FOUND | InputError | precompute was given a credential without a birthdate / birthday disclosure and no explicit birthdayClaimIndex. | Pass birthdayClaimIndex or include the disclosure. |
CLAIM_NOT_FOUND | InputError | A claimRef in a predicate points at an index outside the disclosed claims. | Match claimRef to disclosures order; check Credential.disclosedClaims. |
PARAMS_EXCEEDED | InputError | Inputs overflow JwtCircuitParams (e.g. JWT length > maxMessageLength) or ShowCircuitParams (e.g. more than maxPredicates). | Choose a larger VcSize for JWTs; recompile Show with bigger parameters for more predicates / logic tokens. |
WASM_LOAD_FAILED | WasmError | The bundled WASM module could not be imported. | Pass wasmPath or wasmModule to OpenAC.init. |
WASM_OOM | WasmError | The WASM heap could not grow past memory.maximum. | Raise memory.maximum in OpenACConfig; prefer the native backend for 2k+ keys. |
WASM_NOT_INITIALIZED | WasmError | A method was called before OpenAC.init finished. | Always await OpenAC.init(...) before invoking proving/verification methods. |
Patterns
Distinguish user-recoverable from fatal errors. InputError codes (INVALID_JWT, INVALID_KEY, INVALID_SIGNATURE, MISSING_DISCLOSURE, BIRTHDAY_NOT_FOUND, CLAIM_NOT_FOUND, PARAMS_EXCEEDED) typically mean the caller passed bad data and the wallet should prompt the user. WasmError / SetupError mean the environment is mis-configured and retrying with the same inputs will not help.
Always log the cause. ProofError instances wrap the underlying CLI / WASM exception in error.cause. Surface it in debug logs but do not show it to end users — stack traces often leak filesystem paths.
VerificationResult.error mirrors codes. When OpenAC.verify returns valid: false, the human-readable error string includes the underlying code; verifiers can pattern-match on it for audit logs without throwing.