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

claim.error

Error message

claim.error

What it means

Generic passthrough of a failed task claim: claimTask returned ok:false with an error other than 'blocked_dependency', and that raw error string is rethrown verbatim. Typical values include version conflicts (task.version mismatch) or already-claimed states.

Source

Thrown at src/team/runtime.ts:4714

  if (governance.plan_approval_required && task.requires_code_change === true) {
    const approved = await isTaskApprovedForExecution(sanitized, taskId, cwd);
    if (!approved) {
      throw new Error('plan_approval_required');
    }
  }
  const config = await readTeamConfig(sanitized, cwd);
  if (!config) throw new Error(`Team ${sanitized} not found`);
  const workerInfo = config.workers.find(w => w.name === workerName);
  if (!workerInfo) throw new Error(`Worker ${workerName} not found in team`);
  const dispatchPolicy = resolveDispatchPolicy(manifest?.policy, config.worker_launch_mode);

  const claim = await claimTask(sanitized, taskId, workerName, task.version ?? 1, cwd);
  if (!claim.ok) {
    if (claim.error === 'blocked_dependency') {
      throw new Error(`blocked_dependency:${(claim.dependencies ?? []).join(',')}`);
    }
    throw new Error(claim.error);
  }

  try {
    // Retry dispatch up to 2 times to handle trust prompts during assignment (fixes #393).
    const approvedExecutionState = await resolvePersistedApprovedTeamExecutionContinuityState(
      sanitized,
      config.leader_cwd ?? cwd,
      config.team_state_root ?? resolveCanonicalTeamStateRoot(config.leader_cwd ?? cwd),
    );
    const persistedUltragoalContext = await readPersistedTeamUltragoalContext(
      sanitized,
      config.leader_cwd ?? cwd,
      config.team_state_root ?? resolveCanonicalTeamStateRoot(config.leader_cwd ?? cwd),
    );
    const approvedContextSection = joinContextSections(
      approvedExecutionState.status === 'valid'
        ? buildApprovedTeamHandoffSection(approvedExecutionState.approvedHint)
        : undefined,

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Re-read the task to get its current version and check its status before re-claiming
  2. Serialize assignment of a given task (only one dispatcher) to avoid claim races
  3. Inspect the specific claim.error string to identify the exact claim failure mode

Example fix

// before
await assignTask(team, taskId, worker, cwd); // uses task.version ?? 1

// after
const fresh = await readTask(team, taskId, cwd);
if (!fresh || fresh.status !== 'pending') throw new Error('task no longer claimable');
await claimTask(team, taskId, worker, fresh.version ?? 1, cwd);
Defensive patterns

Strategy: retry

Validate before calling

const fresh = await readTask(teamName, taskId, cwd);
if (fresh?.status !== 'pending') throw new Error('not claimable');

Try / catch

try { await assignTask(t, id, w, cwd); } catch (e) { if (/version|claimed/.test((e as Error).message)) { await sleep(500); await assignTask(t, id, w, cwd); } else throw e; }

Prevention

When it happens

Trigger: Concurrent assignment where another worker claimed the task first (claim token/version mismatch), or the supplied task.version ?? 1 is stale relative to the stored task record.

Common situations: Two dispatchers racing on the same task; retrying assignment with a cached stale task object (old version); task mutated between read and claim.

Related errors


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