Yeachan-Heo/oh-my-codex · warning · Error
sendToWorker: submit_queued_after_tool_call
Error message
sendToWorker: submit_queued_after_tool_call
What it means
After a tool call, the worker's draft line was still queued rather than executed: the pane capture still matches paneHasQueuedCodexSubmission after a final double-Enter attempt. The submission is stuck behind the worker's post-tool-call state, so the library reports submit_queued_after_tool_call instead of silently assuming success.
Source
Thrown at src/team/tmux-session.ts:3870
const [verifyCapture, verifyVisibleCapture] = await Promise.all([
capturePaneAsync(resolveTarget),
captureVisiblePaneAsync(resolveTarget),
]);
if (verifyCapture) {
if (paneHasActiveTask(verifyCapture)) return;
if (
!normalizeWorkerTriggerForDraftMatch(verifyCapture).includes(normalizeWorkerTriggerForDraftMatch(text))
&& !paneHasQueuedCodexSubmission(verifyVisibleCapture)
) {
return;
}
// Draft still visible and no active task — one more Enter attempt.
await sendKeyAsync(resolveTarget, 'Enter');
await sleep(150);
await sendKeyAsync(resolveTarget, 'Enter');
const finalVisibleCapture = await captureVisiblePaneAsync(resolveTarget);
if (paneHasQueuedCodexSubmission(finalVisibleCapture)) {
throw new Error('sendToWorker: submit_queued_after_tool_call');
}
const finalCapture = await capturePaneAsync(resolveTarget);
if (
normalizeWorkerTriggerForDraftMatch(finalCapture).includes(normalizeWorkerTriggerForDraftMatch(text))
&& !paneHasActiveTask(finalCapture)
&& paneLooksReady(finalCapture)
) {
throw new Error('sendToWorker: submit_failed (trigger text still visible after retries)');
}
}
}
export function notifyLeaderStatus(sessionName: string, message: string): boolean {
if (!isTmuxAvailable()) return false;
const trimmed = message.trim();
if (!trimmed) return false;
const capped = trimmed.length > 180 ? `${trimmed.slice(0, 177)}...` : trimmed;
const result = runTmux(['display-message', '-t', sessionName, '--', capped]);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Wait until the pane shows an idle prompt (paneLooksReady / no active task) before submitting
- Retry the whole submit after a delay once the tool call finishes
- Avoid sending triggers while paneHasActiveTask is true
Example fix
// before await sendToWorker(resolveTarget, text); // during tool call // after await waitFor(async () => paneLooksReady(await capturePaneAsync(resolveTarget))); await sendToWorker(resolveTarget, text);
Defensive patterns
Strategy: retry
Validate before calling
const cap = await capturePaneAsync(resolveTarget); if (paneHasActiveTask(cap)) await waitForWorkerIdle(resolveTarget);
Try / catch
try { await submitWorker(resolveTarget, text); } catch (err) { if (!/submit_queued_after_tool_call/.test(String(err))) throw err; await sleep(1500); await submitWorker(resolveTarget, text); } Prevention
- Never send triggers while a tool call is running
- Poll paneLooksReady before submitting
When it happens
Trigger: Sending a trigger while the worker is finishing a tool call; the Enter presses get buffered as a queued Codex submission; final capture still shows the queued draft line, so the error is thrown.
Common situations: Race between tool-call completion and user/leader input; pressing Enter during Codex's spinner state; slow tool execution (npm install, test run) where keystrokes queue up.
Related errors
- sendToWorker: submit_failed (trigger text still visible afte
- invalid auth slot path
- ${label} is not a file: ${path}
- Refusing to overwrite existing ${repoRelative(cwd, missionPa
- shutdown_${scope}_${kind.replaceAll(' ', '_')}_identity_chan
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/a346d7386c6bc428.
Report an issue: GitHub.