ruvnet/ruflo · error · Error
unknown game "${key}". Known: ${Object.keys(GAMES).join(', '
Error message
unknown game "${key}". Known: ${Object.keys(GAMES).join(', ')} What it means
Thrown by getGame() in the ruflo-arena domain when the supplied key is absent from the GAMES registry. The registry (plugins/ruflo-arena/src/domain/games.ts:50) is a fixed Record<string, GameSpec> populated at module load; lookups are exact string matches against its keys. The message lists the known keys at throw time so the caller can see the valid set.
Source
Thrown at plugins/ruflo-arena/src/domain/games.ts:59
{
'0|0': [1, -1],
'1|1': [1, -1],
'0|1': [-1, 1],
'1|0': [-1, 1],
},
true,
);
export const GAMES: Record<string, GameSpec> = {
'prisoners-dilemma': prisonersDilemma,
pd: prisonersDilemma,
'match-or-not': matchOrNot,
mon: matchOrNot,
};
export function getGame(key: string): GameSpec {
const g = GAMES[key];
if (!g) throw new Error(`unknown game "${key}". Known: ${Object.keys(GAMES).join(', ')}`);
return g;
}
View on GitHub (pinned to 6b01dc5a68)
Solutions
- Use one of the exact keys printed in the error message: 'prisoners-dilemma', 'pd', 'match-or-not', or 'mon'.
- If you need a new game, add it to the GAMES Record in games.ts alongside its alias, then call getGame with the new key.
- Normalize inbound input before lookup: trim whitespace, lowercase, and map friendly names to canonical keys.
- Validate the key against Object.keys(GAMES) (or a Zod enum) at the API boundary so the error surfaces as a 400 rather than an uncaught throw.
Example fix
// before
const game = getGame(req.body.gameKey); // throws on typo
// after
import { GAMES, getGame } from './games';
const key = String(req.body.gameKey ?? '').trim().toLowerCase();
if (!(key in GAMES)) {
return res.status(400).json({ error: `unknown game; valid: ${Object.keys(GAMES).join(', ')}` });
}
const game = getGame(key); Defensive patterns
Strategy: validation
Validate before calling
import { GAMES } from './games';
const KNOWN_GAMES = Object.keys(GAMES);
function resolveGame(key: unknown): string | null {
if (typeof key !== 'string') return null;
const k = key.trim().toLowerCase();
return KNOWN_GAMES.includes(k) ? k : null;
}
// before getGame:
const k = resolveGame(input);
if (!k) return res.status(400).json({ error: `valid games: ${KNOWN_GAMES.join(', ')}` }); Type guard
import { GAMES } from './games';
function isKnownGame(key: string): key is keyof typeof GAMES {
return key in GAMES;
} Try / catch
try { const game = getGame(key); } catch (e) { if (e instanceof Error && e.message.startsWith('unknown game')) return res.status(400).json({ error: e.message }); throw e; } Prevention
- Validate user/config game keys against Object.keys(GAMES) at the API boundary.
- Normalize keys (trim + lowercase) before lookup.
- Register both canonical name and alias whenever you add a game.
When it happens
Trigger: Calling getGame(key) with any string that is not one of 'prisoners-dilemma', 'pd', 'match-or-not', or 'mon'. Examples: getGame('prisoner-dilemma') (typo, missing 's'), getGame('rock-paper-scissors') (unregistered game), getGame('PD') (case-sensitive miss), getGame('') (empty).
Common situations: CLI flag or config value with a typo or wrong casing; reusing the canonical name when only the alias is registered (or vice versa); adding a new game spec but forgetting to register it in the GAMES object; user input from an HTTP/form field passed straight into getGame without an allowlist check.
Related errors
- unknown strategy "${name}". Available: ${roster.map((r) => r
- MCP tool not found: ${toolName}
- Invalid completion type
- Invalid hostname
- No models available to build validation schema
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/8d0f5081c1b9e51b.
Report an issue: GitHub.