Yeachan-Heo/oh-my-codex · error · Error

session_id must be a string

Error message

session_id must be a string

What it means

validateSessionId in state-paths throws when session_id is provided but is not a string (number, object, array, boolean). Session IDs are used to build state directory names, so they must be strings matching a strict pattern.

Source

Thrown at src/mcp/state-paths.ts:121

export type StateFileScope = 'root' | 'session';

export interface ModeStateFileRef {
  mode: string;
  path: string;
  scope: StateFileScope;
}

export function normalizeSessionId(sessionId: unknown): string | undefined {
  if (typeof sessionId !== 'string') return undefined;
  const normalized = sessionId.trim();
  return SESSION_ID_PATTERN.test(normalized) ? normalized : undefined;
}

export function validateSessionId(sessionId: unknown): string | undefined {
  if (sessionId == null) return undefined;
  if (typeof sessionId !== 'string') {
    throw new Error('session_id must be a string');
  }
  if (!SESSION_ID_PATTERN.test(sessionId)) {
    throw new Error('session_id must match ^[A-Za-z0-9_-]{1,64}$');
  }
  return sessionId;
}


export function validateStateModeSegment(mode: unknown): string {
  if (typeof mode !== 'string') {
    throw new Error('mode must be a string');
  }
  const normalized = mode.trim();
  if (!normalized) {
    throw new Error('mode must be a non-empty string');
  }
  if (normalized.includes('..')) {
    throw new Error('mode must not contain ".."');

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Convert the ID to a string before calling: String(sessionId)
  2. Fix the producer so session_id is serialized as a JSON string
  3. Add a type guard on the boundary of your client code

Example fix

// before
validateSessionId(12345);
// after
validateSessionId(String(12345)); // "12345"
Defensive patterns

Strategy: type-guard

Validate before calling

if (sessionId != null && typeof sessionId !== 'string') sessionId = String(sessionId);

Type guard

function isSessionIdInput(v: unknown): v is string | undefined | null { return v == null || typeof v === 'string'; }

Try / catch

try { validateSessionId(id); } catch (e) { if ((e as Error).message === 'session_id must be a string') id = String(id); else throw e; }

Prevention

When it happens

Trigger: Passing session_id: 12345 (number from a JSON producer that dropped quotes), session_id: {id: "x"}, or an array. null/undefined is allowed and returns undefined; any other non-string type throws.

Common situations: JSON serialization losing string quoting for numeric-looking IDs; forwarding IDs from a database as numbers; LLM tool calls emitting numbers for IDs.

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/c98a59ba28bc6373. Report an issue: GitHub.