Files
suaveplan/packages/security-stack/security/tpm-struct/src/errors/error-codes.md
2026-05-27 23:47:53 +01:00

3.5 KiB

errors/error-codes — TPM_STRUCT error registry

(no submodules)

Purpose

The errors module ships the canonical defineCodes("TPM_STRUCT", [...]) registry (10 codes) and the TpmStructError extends SuaveplanError<TpmStructErrorCode> base class every other module throws from. Stable codes are non-negotiable: consumers (WebAuthn verifiers, attestation gateways, log scrapers) branch on err.code to distinguish "buffer was short" from "magic prefix wrong" from "the registered code I care about for my dashboard." A registry with a fixed alphabet is also what makes the tpm_struct.parse_errors_total{code} OTel counter bounded.

Features

  • Ten registered codes covering every failure class from §8.3 (object attributes), §10.x (attest), §11.x (algorithm and curve), §12.x (public area), and §16 (name).
  • TpmStructError extends SuaveplanError<TpmStructErrorCode> so instanceof narrows the .code union.
  • tpmStructError(code, message, detail?) helper attaches a structured detail payload (cursor, requested length, Zod issues) to the cause chain so log adapters can format failures without downcasting.

Usage: Basic Example

import {
    TPM_STRUCT_CODES,
    TpmStructError,
    tpmStructError,
} from "@suaveplan/tpm-struct/errors";

try {
    // ... parser code
} catch (e) {
    if (e instanceof TpmStructError) {
        console.error(`tpm-struct failure: ${e.code}`);
        if (e.code === TPM_STRUCT_CODES.TRUNCATED) {
            // recoverable: ask the upstream for a longer buffer
        }
    }
}
void tpmStructError;

Usage: Advanced Example

import {
    TPM_STRUCT_CODES,
    TpmStructError,
} from "@suaveplan/tpm-struct/errors";

type ParseFailureMetric = "magic" | "truncated" | "alg" | "curve" | "other";

function classify(err: TpmStructError): ParseFailureMetric {
    switch (err.code) {
        case TPM_STRUCT_CODES.MAGIC_INVALID:
            return "magic";
        case TPM_STRUCT_CODES.TRUNCATED:
            return "truncated";
        case TPM_STRUCT_CODES.ALG_UNSUPPORTED:
            return "alg";
        case TPM_STRUCT_CODES.CURVE_UNSUPPORTED:
            return "curve";
        default:
            return "other";
    }
}

// `cause.detail` carries the structured failure context.
function reportTruncated(err: TpmStructError) {
    const detail =
        ((err as unknown as { cause?: { detail?: Record<string, unknown> } })
            .cause?.detail) ?? {};
    return { cursor: detail.cursor, requested: detail.requested };
}

API Reference

  • TPM_STRUCT_CODES — frozen registry: MAGIC_INVALID, TRUNCATED, ALG_UNSUPPORTED, CURVE_UNSUPPORTED, TYPE_MISMATCH, MALFORMED, NAME_ALG_NULL, ATTEST_TYPE_UNSUPPORTED, PARAMETERS_INVALID, OBJECT_ATTRIBUTES_RESERVED_NONZERO. Each value is the literal TPM_STRUCT.<NAME>.
  • TpmStructError — base class, message is always prefixed with the code literal.
  • TpmStructErrorCode — literal union of the ten code strings.
  • tpmStructError(code, message, detail?) — convenience constructor; detail (when provided) is wrapped in an Error so it survives through the cause chain.

Implementation Notes

The error message is always prefixed with the code literal so log scrapers find a stable substring without inspecting .code. Non-Error detail payloads are wrapped in a synthetic Error carrying a detail slot — this preserves the standard ECMAScript Error.cause shape while still surfacing structured fields downstream code can read.