Yeachan-Heo/oh-my-codex · warning · Error
shutdown_rejected:${detail}
Error message
shutdown_rejected:${detail} What it means
During the worker-ack phase of shutdown (when skipWorkerAcks is false), one or more workers explicitly rejected the shutdown and force was not set. The message lists each rejecting worker and its reason as 'worker:reason' pairs.
Source
Thrown at src/team/runtime.ts:5064
for (const w of config.workers) {
const ack = await readShutdownAck(sanitized, w.name, cwd, shutdownRequestTimes.get(w.name));
if (ack && !ackedWorkers.has(w.name)) {
ackedWorkers.add(w.name);
await appendTeamEvent(sanitized, {
type: 'shutdown_ack',
worker: w.name,
reason: ack.status === 'reject' ? `reject:${ack.reason || 'no_reason'}` : 'accept',
}, cwd);
}
if (ack?.status === 'reject') {
if (!rejected.some((r) => r.worker === w.name)) {
rejected.push({ worker: w.name, reason: ack.reason || 'no_reason' });
}
}
}
if (rejected.length > 0 && !force) {
const detail = rejected.map(r => `${r.worker}:${r.reason}`).join(',');
throw new Error(`shutdown_rejected:${detail}`);
}
const anyAlive = config!.workers.some((w) => (
config!.worker_launch_mode === 'prompt'
? isPromptWorkerAlive(config!, w)
: isWorkerAlive(sessionName, w.index, w.pane_id, w.pid, config!.tmux_pane_owner_id ?? undefined, config!.hud_pane_id ?? undefined)
));
if (!anyAlive) break;
// Sleep 2s
await new Promise(resolve => setTimeout(resolve, 2000));
}
const anyAliveAfterWait = config!.workers.some((w) => (
config!.worker_launch_mode === 'prompt'
? isPromptWorkerAlive(config!, w)
: isWorkerAlive(sessionName, w.index, w.pane_id, w.pid, config!.tmux_pane_owner_id ?? undefined, config!.hud_pane_id ?? undefined)
));
if (anyAliveAfterWait && !force) {View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Inspect the per-worker reasons in the message and address them (finish tasks, answer prompts, restart a wedged worker)
- Re-run shutdown after the workers stop rejecting; use force to override deliberate holds
- If a single worker is wedged, restart it and retry the graceful shutdown
Example fix
# before omx team shutdown myteam # error: shutdown_rejected:worker-2:task_in_progress # after omx team task wait myteam --all omx team shutdown myteam # or: omx team shutdown myteam --force
Defensive patterns
Strategy: retry
Validate before calling
const acks = await pollWorkerAcks(teamName, cwd);
if (acks.some(a => !a.ok)) throw new Error('workers will reject; drain work first'); Try / catch
try { await shutdownTeam(t, cwd, {}); } catch (e) { const m = /^shutdown_rejected:(.+)$/.exec((e as Error).message); if (m) { await resolveRejectingWorkers(t, m[1]); await shutdownTeam(t, cwd, {}); } else throw e; } Prevention
- Drain in-flight work before shutdown
- Answer worker prompts promptly
- Use force only with explicit operator intent
When it happens
Trigger: Calling shutdown without force while at least one alive worker returns a rejection ack (a non-ok ack.reason) during the acknowledgement round.
Common situations: A worker agent mid-task rejects shutdown to protect in-flight work; worker prompts require interactive confirmation; one unresponsive/misbehaving worker returns a rejection reason.
Related errors
- Usage: omx team shutdown <team-name> [--force] [--confirm-is
- shutdown_config_missing:${config.name}
- shutdown_config_missing_after_commit:${current.name}
- shutdown_shared_session_worker_owner_unavailable:${paneId}:$
- shutdown_config_missing_after_detached_reconciliation:${sani
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/7941d597b2265540.
Report an issue: GitHub.