# serialize-error ## Purpose Defines the error hierarchy for `@suaveplan/serialize`. All errors thrown by this package extend `SerializationError`, which in turn extends `SuaveplanError` from `@suaveplan/error`. This design ensures every thrown error carries a stable, machine-readable code string (`SERIALIZE.*`) so callers can programmatically distinguish between circular references, depth overflows, size overflows, and unknown type tags without parsing human-readable messages. The contextual payload (`SerializationErrorContext`) transports structural metadata — tag names, recursion depths, byte sizes, and dot-path strings — that would otherwise require expensive re-traversal to reconstruct after the fact. ## Features - `SerializationError` — base class; extends `SuaveplanError` with an optional `SerializationErrorContext` - `CircularReferenceError` — emitted when a cycle is detected in the input object graph; includes the dot-path where the cycle was encountered - `MaxDepthExceededError` — emitted when recursion depth exceeds the caller-configured `maxDepth`; includes the depth value - `MaxSizeExceededError` — emitted when the serialized byte count exceeds `maxSize`; includes the approximate size in bytes - `UnsupportedTypeError` — emitted during deserialization when a `__t` tag has no registered decoder; includes the unknown tag string - Exported `SerializationErrorCode` union type for exhaustive `switch` narrowing - Re-exported `SERIALIZE_CODES` constant map for use in tests and error construction ## Usage: Basic Example ```typescript import { CircularReferenceError, MaxDepthExceededError, SerializationError, } from "@suaveplan/serialize"; try { // serialization call here } catch (err) { if (err instanceof CircularReferenceError) { console.error("Cycle at", err.context?.path); } else if (err instanceof SerializationError) { console.error("Serialization failed:", err.code); } } ``` ## Usage: Advanced Example ```typescript import { SERIALIZE_CODES, SerializationError, UnsupportedTypeError, type SerializationErrorCode, } from "@suaveplan/serialize"; function handleSerializeError(err: unknown): never { if (!(err instanceof SerializationError)) throw err; const code: SerializationErrorCode = err.code; switch (code) { case SERIALIZE_CODES["CODEC.CIRCULAR_REFERENCE"]: throw new Error(`Cycle at path: ${err.context?.path ?? "unknown"}`); case SERIALIZE_CODES["CODEC.MAX_DEPTH"]: throw new Error(`Too deep: ${err.context?.depth}`); case SERIALIZE_CODES["CODEC.MAX_SIZE"]: throw new Error(`Too large: ${err.context?.size} bytes`); case SERIALIZE_CODES["CODEC.UNKNOWN_TAG"]: throw new Error(`No decoder for tag: ${err.context?.tag}`); default: throw err; } } // UnsupportedTypeError carries the unknown tag const e = new UnsupportedTypeError("__MyCustomClass"); console.log(e.context?.tag); // "__MyCustomClass" ``` ## API Reference ### `SerializationError` ```typescript class SerializationError extends SuaveplanError { constructor( code: SerializationErrorCode, messageKey: string, options?: SerializationErrorOptions, ): void } ``` - `code` — one of the `SERIALIZE.*` codes - `messageKey` — i18n key resolved via `@suaveplan/error` resolver - `options.cause` — underlying error, chained via `Error.cause` - `options.context` — `SerializationErrorContext` metadata ### `CircularReferenceError` ```typescript new CircularReferenceError(path?: string, cause?: unknown) ``` Code: `SERIALIZE.CODEC.CIRCULAR_REFERENCE`. `context.path` is the dot-path string where the cycle was detected. ### `MaxDepthExceededError` ```typescript new MaxDepthExceededError(depth: number, cause?: unknown) ``` Code: `SERIALIZE.CODEC.MAX_DEPTH`. `context.depth` is the depth value at which encoding was aborted. ### `MaxSizeExceededError` ```typescript new MaxSizeExceededError(size: number, cause?: unknown) ``` Code: `SERIALIZE.CODEC.MAX_SIZE`. `context.size` is the approximate byte count. ### `UnsupportedTypeError` ```typescript new UnsupportedTypeError(tag: string, cause?: unknown) ``` Code: `SERIALIZE.CODEC.UNKNOWN_TAG`. `context.tag` is the unrecognised tag string. ### `SerializationErrorContext` ```typescript interface SerializationErrorContext { tag?: string; depth?: number; size?: number; path?: string; } ``` ### `SerializationErrorOptions` ```typescript interface SerializationErrorOptions { cause?: unknown; context?: SerializationErrorContext; } ``` ### `SerializationErrorCode` Union type of all `SERIALIZE.*` code strings; use with exhaustive `switch` statements. ## Implementation Notes - `SerializationError` maps `SerializationErrorOptions.context` to the generic `Record` shape expected by `SuaveplanErrorOptions` without widening the exported interface — callers always get the narrow `SerializationErrorContext` type. - Each subclass uses a specific constructor signature (only the meaningful fields, not the full code/key/options triple) to make throw sites readable and to prevent code/message mismatches. - The `SERIALIZE_CODES` constant is defined in a separate `codes.ts` module and re-exported from here so that the error file is self-contained for consumers who only import errors.