# GameServerError _(no submodules)_ ## Purpose `GameServerError` is the single typed-exception class for the `@suaveplan/game-server` package. It extends `SuaveplanError` from `@suaveplan/error`, anchoring every failure raised by the server framework to a stable, lint-checkable code string in the `GAME_SERVER.*` namespace. Callers can branch on `error.code` without depending on `instanceof` semantics that fail across module realms. The companion `GAME_SERVER_CODES` constant is produced by `defineCodes("GAME_SERVER", [...])` so the registry is verified at compile time and contributes its codes to the global suaveplan error catalog. The registry only enumerates codes that an actual production code path throws today — follow-up migrations (engine, state, matchmaking, telemetry, network) extend the array as their throw sites land, in line with `AGENTS.md` §13. ## Features - Single typed error class for the entire package. - Codes resolved through `@suaveplan/error`'s `defineCodes` registry. - Optional `cause` and `context` for chained diagnostics. - Compile-time exhaustiveness on the `GameServerCode` union. - Code namespace `GAME_SERVER.*` is reserved for this package across the workspace. ## Usage: Basic ```typescript import { GAME_SERVER_CODES, GameServerError, } from "@suaveplan/game-server/errors"; try { container.resolve("missing"); } catch (err) { if ( err instanceof GameServerError && err.code === GAME_SERVER_CODES.SERVICE_NOT_REGISTERED ) { // recover by registering a fallback } } ``` ## Usage: Advanced ```typescript import { GameServerError, GAME_SERVER_CODES } from "@suaveplan/game-server/errors"; function loadConfig(input: unknown) { const parsed = GameConfigSchema.safeParse(input); if (!parsed.success) { throw new GameServerError( GAME_SERVER_CODES.INVALID_GAME_CONFIG, "Game config failed Zod validation", { cause: parsed.error, context: { input } }, ); } return parsed.data; } ``` The optional `context` bag is logged by the standard `@suaveplan/logger` formatter and forwarded as OpenTelemetry span attributes by `@suaveplan/opentelemetry`, so diagnostic data flows without bespoke wiring. ## API Reference ### `GAME_SERVER_CODES` A frozen object of code constants: - `SERVICE_NOT_REGISTERED` — thrown by `DIContainer.resolve` on an unknown identifier. - `INVALID_GAME_CONFIG` / `INVALID_SESSION_METADATA` / `INVALID_PLAYER_INFO` — thrown by the corresponding `parse*` boundary functions in `./types`. - `INVALID_MOVE` — `AbstractGameLogic.processMove` validation failure. - `PLAYER_ALREADY_EXISTS` / `PLAYER_NOT_FOUND` — `AbstractGameLogic.{addPlayer,removePlayer}`. - `LISTENER_LIMIT_EXCEEDED` / `INVALID_LISTENER_COUNT` / `EVENT_WAIT_TIMEOUT` — `GameEventEmitter`. - `STATE_DIFF_FAILED` / `STATE_PATCH_FAILED` / `STATE_RESTORE_FAILED` / `INVALID_SNAPSHOT` / `STATE_DECOMPRESS_FAILED` / `STATE_SYNC_TRANSPORT_FAILED` — state-manager / differ / compressor / sync. - `TRANSPORT_ALREADY_INITIALIZED` / `TRANSPORT_NOT_INITIALIZED` / `TRANSPORT_NOT_CONNECTED` / `INVALID_MESSAGE_FORMAT` / `RECONNECT_EXHAUSTED` / `RECONNECT_IN_PROGRESS` — network adapter + reconnection manager + transports. - `ENGINE_NOT_STARTED` — engine method called before `start()`. - `ENGINE_ALREADY_STARTED` — second `start()` call on a live engine. - `ENGINE_DISPOSED` — engine method called after `dispose()`. - `INVALID_ENGINE_OPTIONS` — Zod failure on `GameEngineOptions`. - `INVALID_GAME_LOOP_OPTIONS` — Zod failure on `GameLoopOptions`. - `GAME_LOOP_NOT_RUNNING` — `pause`/`resume`/`stop` called on an idle loop. - `GAME_LOOP_ALREADY_RUNNING` — second `start()` call on a running loop. - `PLUGIN_NOT_FOUND` — `uninstall`, `enable`, `disable`, `get` on an unknown plugin name. - `DUPLICATE_PLUGIN` — `install` called with an already-registered plugin name. - `PLUGIN_LIFECYCLE_FAILED` — wraps any error thrown from a plugin lifecycle hook. - `MATCHMAKING_QUEUE_FULL` — `QueueManager.addToQueue` rejected because the per-key queue is at the configured cap. - `INVALID_QUEUE_REQUEST` — Zod failure on a `QueueRequest` arriving at `QueueManager` / `MatchmakingEngine`. - `INVALID_MATCH_CRITERIA` — Zod failure on a `MatchCriteria` arriving at `MatchmakingEngine.createMatch`. - `NO_MATCH_FOUND` — `MatchmakingEngine.createMatch` returned `null` when the caller requested `throwOnNoMatch`. - `INVALID_SKILL_SCORE` — `SkillMatcher` received a non-finite rating or seeker missing a positive `waitingSince`. - `SPECTATOR_LIMIT_REACHED` — `SpectatorManager.addSpectator` rejected because the session is at its spectator cap. - `INVALID_SPECTATOR_REQUEST` — Zod failure on `SpectatorPermissions` or duplicate spectator id. - `UNKNOWN_MATCHING_ALGORITHM` — `MatchmakingEngine.createMatch` was passed an algorithm string outside the registered union. - `POOL_EXHAUSTED` — `ObjectPool.acquire` rejected because the pool's `maxSize` is reached and no slots are free. - `POOL_DISPOSED` — `ObjectPool` method called after `dispose()`. - `RELEASE_FOREIGN_OBJECT` — `ObjectPool.release` received an object that did not originate from this pool. - `INVALID_POOL_CONFIG` — `ObjectPool` constructor received a non-positive `initialSize` / `maxSize`, or `maxSize` smaller than `initialSize`. - `INVALID_TIER_CONFIG` — `NetworkTierAdapter` constructor received an empty / malformed tier list or a node-capability with a non-finite score. - `UNKNOWN_TIER` — `NetworkTierAdapter` queried for a tier index / node-type that is not registered. Each value is the fully-qualified string e.g. `"GAME_SERVER.SERVICE_NOT_REGISTERED"`. The latter six codes are introduced by Wave A (core foundation): `INVALID_MOVE` fires from `AbstractGameLogic.processMove` when validation fails; `PLAYER_ALREADY_EXISTS` / `PLAYER_NOT_FOUND` from `addPlayer` / `removePlayer`; `LISTENER_LIMIT_EXCEEDED` / `INVALID_LISTENER_COUNT` / `EVENT_WAIT_TIMEOUT` from `GameEventEmitter`. The state-domain codes added in Wave B-3 (`STATE_*`, `INVALID_SNAPSHOT`) are thrown by the `state-manager`, `state-differ`, `delta-compressor`, and `state-sync` modules. `STATE_DIFF_FAILED` and `STATE_PATCH_FAILED` wrap unexpected exceptions raised while walking deeply-nested structures; `STATE_RESTORE_FAILED` and `INVALID_SNAPSHOT` surface when callers try to restore a snapshot whose shape disagrees with the manager's state schema; `STATE_DECOMPRESS_FAILED` wraps malformed wire packets; and `STATE_SYNC_TRANSPORT_FAILED` flags transport-layer send/receive faults. ### `type GameServerCode` Union of all fully-qualified code strings in the registry. ### `new GameServerError(code, message, options?)` - `code`: `GameServerCode` - `message`: `string` - `options?`: `{ cause?: unknown; context?: Record }` Instances expose `.code`, `.message`, `.cause` (or `undefined`), `.context` (or `undefined` when not supplied), and `.name === "GameServerError"`. ## Implementation Notes `SuaveplanError` is parameterised over a code union, so removing a code from the `defineCodes` literal array produces a TypeScript error at every throw site — this is the lint-checkable contract that keeps the registry minimal and honest. Codes are flat strings (no nesting) because `@suaveplan/error`'s canonical form is a single dot-delimited identifier. The class explicitly sets `this.name` because subclasses of `Error` inherit the parent name in some runtimes; downstream log scrapers key on the exact string `"GameServerError"`.