{"record":{"id":"7941d597b2265540","repo":"Yeachan-Heo/oh-my-codex","slug":"shutdown-rejected-detail","errorCode":null,"errorMessage":"shutdown_rejected:${detail}","messagePattern":"shutdown_rejected:(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/team/runtime.ts","lineNumber":5064,"sourceCode":"      for (const w of config.workers) {\n        const ack = await readShutdownAck(sanitized, w.name, cwd, shutdownRequestTimes.get(w.name));\n        if (ack && !ackedWorkers.has(w.name)) {\n          ackedWorkers.add(w.name);\n          await appendTeamEvent(sanitized, {\n            type: 'shutdown_ack',\n            worker: w.name,\n            reason: ack.status === 'reject' ? `reject:${ack.reason || 'no_reason'}` : 'accept',\n          }, cwd);\n        }\n        if (ack?.status === 'reject') {\n          if (!rejected.some((r) => r.worker === w.name)) {\n            rejected.push({ worker: w.name, reason: ack.reason || 'no_reason' });\n          }\n        }\n      }\n      if (rejected.length > 0 && !force) {\n        const detail = rejected.map(r => `${r.worker}:${r.reason}`).join(',');\n        throw new Error(`shutdown_rejected:${detail}`);\n      }\n\n      const anyAlive = config!.workers.some((w) => (\n        config!.worker_launch_mode === 'prompt'\n          ? isPromptWorkerAlive(config!, w)\n          : isWorkerAlive(sessionName, w.index, w.pane_id, w.pid, config!.tmux_pane_owner_id ?? undefined, config!.hud_pane_id ?? undefined)\n      ));\n      if (!anyAlive) break;\n      // Sleep 2s\n      await new Promise(resolve => setTimeout(resolve, 2000));\n    }\n\n    const anyAliveAfterWait = config!.workers.some((w) => (\n      config!.worker_launch_mode === 'prompt'\n        ? isPromptWorkerAlive(config!, w)\n        : isWorkerAlive(sessionName, w.index, w.pane_id, w.pid, config!.tmux_pane_owner_id ?? undefined, config!.hud_pane_id ?? undefined)\n    ));\n    if (anyAliveAfterWait && !force) {","sourceCodeStart":5046,"sourceCodeEnd":5082,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/team/runtime.ts#L5046-L5082","documentation":"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.","triggerScenarios":"Calling shutdown without force while at least one alive worker returns a rejection ack (a non-ok ack.reason) during the acknowledgement round.","commonSituations":"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.","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"],"exampleFix":"# before\nomx team shutdown myteam\n# error: shutdown_rejected:worker-2:task_in_progress\n\n# after\nomx team task wait myteam --all\nomx team shutdown myteam  # or: omx team shutdown myteam --force","handlingStrategy":"retry","validationCode":"const acks = await pollWorkerAcks(teamName, cwd);\nif (acks.some(a => !a.ok)) throw new Error('workers will reject; drain work first');","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Drain in-flight work before shutdown","Answer worker prompts promptly","Use force only with explicit operator intent"],"tags":["shutdown","worker-acks","rejection"],"backgroundTag":"graceful-shutdown-rejected","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}