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

Invalid task ID: "${taskId}". Must be a positive integer (di

Error message

Invalid task ID: "${taskId}". Must be a positive integer (digits only, max 20 digits).

What it means

Task ID failed TASK_ID_SAFE_PATTERN: it must be a positive integer expressed as digits only, at most 20 digits (no signs, decimals, or non-numeric characters). Thrown by validateTaskId via taskClaimLockDir, approvalPath, and taskFilePath.

Source

Thrown at src/team/state.ts:508

function assertPathWithinDir(filePath: string, rootDir: string): void {
  const normalizedRoot = resolve(rootDir);
  const normalizedPath = resolve(filePath);
  if (normalizedPath !== normalizedRoot && !normalizedPath.startsWith(normalizedRoot + sep)) {
    throw new Error('Path traversal detected: path is outside the allowed directory');
  }
}

function validateWorkerName(name: string): void {
  if (!WORKER_NAME_SAFE_PATTERN.test(name)) {
    throw new Error(
      `Invalid worker name: "${name}". Must match /^[a-z0-9][a-z0-9-]{0,63}$/ (lowercase alphanumeric + hyphens, max 64 chars).`
    );
  }
}

function validateTaskId(taskId: string): void {
  if (!TASK_ID_SAFE_PATTERN.test(taskId)) {
    throw new Error(
      `Invalid task ID: "${taskId}". Must be a positive integer (digits only, max 20 digits).`
    );
  }
}

function defaultLeader(): TeamLeader {
  return {
    session_id: '',
    worker_id: 'leader-fixed',
    role: 'coordinator',
  };
}

function defaultTmuxPaneOwnerId(teamName: string): string {
  return `team:${teamName}`;
}

function defaultPolicy(

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Extract the numeric portion (e.g. parseInt/regex '^\\d+$') and pass it as a canonical decimal string
  2. Validate ids at input boundaries with /^\d{1,20}$/ before calling these APIs
  3. Reject or remap non-numeric external identifiers instead of passing them through

Example fix

// before
const p = taskFilePath(`task-${id}`, ...); // throws

// after
const numericId = String(id).replace(/^\D+/, '');
if (!/^\d{1,20}$/.test(numericId)) throw new Error('invalid task id');
const p = taskFilePath(numericId, ...);
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizeTaskId(raw: string | number): string | null {
  const s = typeof raw === 'number' ? String(Math.trunc(raw)) : raw;
  return /^\d{1,20}$/.test(s) && !/^0/.test(s) === false ? (s === '0' ? null : s) : (/^[1-9]\d{0,19}$/.test(s) ? s : null);
}

Type guard

function isValidTaskId(taskId: string): boolean {
  return /^[1-9]\d{0,19}$|^0$/.test(taskId) && /^\d{1,20}$/.test(taskId);
}

Prevention

When it happens

Trigger: Passing task ids like 'task-12', '12.0', '-5', a UUID, or an empty string to taskClaimLockDir, approvalPath, or taskFilePath.

Common situations: External systems using UUID or prefixed ids mapped directly to task ids; parsing ids from strings without stripping prefixes; numeric ids serialized as floats.

Related errors


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