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

Timed out acquiring task claim lock for ${teamName}/${taskId

Error message

Timed out acquiring task claim lock for ${teamName}/${taskId}

What it means

Thrown by the task claim lock acquisition in scaling.ts: after stale-lock takeover attempts, the named team/task claim lock could not be acquired within the timeout window.

Source

Thrown at src/team/scaling.ts:139

    taskClaimLockDir: (name: string, taskId: string, lockCwd: string) => (
      join(teamDir(name, lockCwd), 'claims', `task-${taskId}.lock`)
    ),
    mailboxLockDir: (name: string, workerName: string, lockCwd: string) => (
      join(teamDir(name, lockCwd), 'mailbox', `.lock-${workerName}`)
    ),
  };
  const acquire = async (index: number): Promise<T> => {
    if (index >= uniqueTaskIds.length) return await fn();
    const taskId = uniqueTaskIds[index]!;
    const locked = await withTaskClaimLock(
      teamName,
      taskId,
      cwd,
      TASK_CLAIM_LOCK_STALE_MS,
      locks,
      async () => await acquire(index + 1),
    );
    if (!locked.ok) throw new Error(`Timed out acquiring task claim lock for ${teamName}/${taskId}`);
    return locked.value;
  };
  return await acquire(0);
}

// ── Environment gate ──────────────────────────────────────────────────────────

const OMX_TEAM_SCALING_ENABLED_ENV = 'OMX_TEAM_SCALING_ENABLED';
const WORKTREE_TRIGGER_STATE_ROOT = '$OMX_TEAM_STATE_ROOT';

export function isScalingEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
  const raw = env[OMX_TEAM_SCALING_ENABLED_ENV];
  if (!raw) return false;
  const normalized = raw.trim().toLowerCase();
  return ['1', 'true', 'yes', 'on', 'enabled'].includes(normalized);
}

type ScalePaneInstance = {

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Check for a live process holding the claim lock (lock file records pid) and let it finish or kill it
  2. Retry after the stale window elapses so the lock can be taken over
  3. Avoid having multiple workers claim the identical taskId simultaneously
Defensive patterns

Strategy: retry

Validate before calling

// Check for a live lock holder before claiming
const lockInfo = await readTaskClaimLock(teamName, taskId);
if (lockInfo?.pid && isPidAlive(lockInfo.pid)) deferClaim();

Try / catch

try { await withTaskClaimLocks(...) } catch (e) { if (e.message.includes('Timed out acquiring task claim lock')) await sleep(backoff).then(retry); else throw e; }

Prevention

When it happens

Trigger: Acquiring task claim locks (directly or via withTaskClaimLocks) when another process holds the lock for teamName/taskId and does not release it within TASK_CLAIM_LOCK_STALE_MS plus retry budget.

Common situations: Concurrent workers claiming the same task, a crashed process leaving a lock considered live, or heavy contention on the same task.

Understand the failure class

Related errors


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