Files
skills/docs/foundation/flow/fsm/src/errors/fsm-error.md
2026-05-29 08:20:56 +01:00

3.6 KiB

fsm-error

(no submodules)

Purpose

Defines the stable error-code registry and typed error class for the @suaveplan/fsm package. Every error thrown by the FSM interpreter, definition validator, and context helpers extends FSMError, giving callers a single instanceof check and a machine-readable code property drawn from FSM_CODES.

The registry is built with defineCodes from @suaveplan/error, which guarantees that each code string is unique across the entire @suaveplan/* ecosystem and can be compared with === without string literals.

Features

  • Five stable error codes covering all failure scenarios: INVALID_DEFINITION, INVALID_TRANSITION, INVALID_STATE, GUARD_FAILED, ACTION_ERROR
  • FSMError extends SuaveplanError<FSMCode> for narrow discriminated-union typing
  • Supports optional cause and context metadata on every error instance
  • Fully compatible with the @suaveplan/error wire-format serialization

Usage: Basic Example

import { FSMError, FSM_CODES } from '@suaveplan/fsm/errors';

try {
  machine.send('UNKNOWN_EVENT');
} catch (err) {
  if (err instanceof FSMError) {
    console.error(err.code, err.message);
    // "FSM.INVALID_TRANSITION" "No valid transition for event in current state"
  }
}

Usage: Advanced Example

import { FSMError, FSM_CODES } from '@suaveplan/fsm/errors';

function handleFSMError(err: unknown): void {
  if (!(err instanceof FSMError)) throw err;

  switch (err.code) {
    case FSM_CODES.INVALID_DEFINITION:
      console.error('Machine definition is malformed:', err.message);
      break;
    case FSM_CODES.INVALID_TRANSITION:
      console.warn('Event not handled in current state');
      break;
    case FSM_CODES.GUARD_FAILED:
      console.info('Transition blocked by guard');
      break;
    case FSM_CODES.ACTION_ERROR:
      console.error('Action threw during transition:', err.cause);
      break;
    default:
      throw err;
  }
}

API Reference

FSM_CODES

const FSM_CODES: {
  INVALID_DEFINITION: 'FSM.INVALID_DEFINITION';
  INVALID_TRANSITION: 'FSM.INVALID_TRANSITION';
  INVALID_STATE:      'FSM.INVALID_STATE';
  GUARD_FAILED:       'FSM.GUARD_FAILED';
  ACTION_ERROR:       'FSM.ACTION_ERROR';
}

Stable string constants for each FSM error domain. Use these instead of raw string comparisons to benefit from TypeScript narrowing.

type FSMCode

Union type of all values in FSM_CODES. Used as the generic parameter of FSMError.

class FSMError

class FSMError extends SuaveplanError<FSMCode> {
  constructor(
    code: FSMCode,
    message: string,
    options?: { cause?: Error; context?: Record<string, unknown> }
  )
}

Parameters:

  • code — one of the FSM_CODES values; stored as this.code
  • message — human-readable description of the failure
  • options.cause — underlying error that triggered this one (chained)
  • options.context — arbitrary key/value metadata (state name, event type, etc.)

Throws: Never (constructor only).

Implementation Notes

The defineCodes helper from @suaveplan/error namespaces all codes under "FSM." to prevent collisions with codes from other packages sharing the same registry. The as const assertion on the descriptor object ensures the resulting type is a fully-discriminated union rather than string.

The noUselessConstructor biome lint suppression is intentional: the constructor is required to widen the protected base constructor to public, which is a documented pattern in this repository for all SuaveplanError subclasses.