jackwener/OpenCLI · error · CommandExecutionError
Failed to send message
Error message
Failed to send message
What it means
This CommandExecutionError is thrown by the `claude send` command when sendMessage reports failure — the error message is sendResult.reason if provided, otherwise the generic 'Failed to send message'. It means the prompt could not be injected/submitted into the composer and sent, despite the composer being present.
Source
Thrown at clis/claude/send.js:40
const prompt = requireNonEmptyPrompt(kwargs.prompt, 'claude send');
if (parseBoolFlag(kwargs.new)) {
await page.goto(CLAUDE_URL);
try {
await page.wait({ selector: COMPOSER_SELECTOR, timeout: 8 });
} catch {
// Composer didn't mount; ensureClaudeComposer below surfaces a typed error.
}
} else {
// ensureOnClaude now waits for the composer selector; the previous
// post-nav 2 s settle is covered by that event-based wait.
await ensureOnClaude(page);
}
await withRetry(() => ensureClaudeComposer(page, 'Claude send requires a visible composer on the current page.'));
const sendResult = await withRetry(() => sendMessage(page, prompt));
if (!sendResult?.ok) {
throw new CommandExecutionError(sendResult?.reason || 'Failed to send message');
}
return [{
Status: 'Success',
SubmittedBy: sendResult.method || 'send-button',
InjectedText: prompt,
}];
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Read sendResult.reason in the message (when present) for the specific cause and address it directly
- Re-run the command — transient composer/submit races are often resolved on retry, and withRetry already retried the immediate window
- Shorten the prompt if it may exceed Claude's message limits, and verify the conversation isn't full/at capacity
- Refresh the conversation page in the automated browser (or rerun the command to reopen) so a stale DOM is replaced
- Update the library if Claude changed its composer/send-button markup
Example fix
// before opencli claude send "<very long prompt>" // send button disabled -> Failed to send message // after opencli claude send "shorter prompt" # retry with valid-length prompt after page settles
Defensive patterns
Strategy: retry
Validate before calling
// preflight: composer must exist and the prompt must be non-empty/reasonable
if (!prompt || prompt.length > 100000) throw new Error('Prompt missing or too long for claude.ai');
const state = await getPageState(page);
if (!state.isLoggedIn) throw new Error('Run `opencli claude auth` first'); Type guard
function isSendSuccess(sendResult) {
return !!sendResult && sendResult.ok === true && typeof sendResult.method === 'string';
} Try / catch
try {
await opencli.claude.send(prompt);
} catch (e) {
if (e.message === 'Failed to send message' || e.message.startsWith('send failed')) {
await sleep(2000);
return opencli.claude.send(prompt); // one retry after page settles
}
throw e;
} Prevention
- Keep prompts within Claude's message size limits and verify the conversation isn't full
- Retry once after a short delay — send races are common on freshly loaded pages
- Refresh/reopen the conversation page if the DOM may be stale
- Update the library when Claude changes composer/send-button markup
When it happens
Trigger: withRetry(() => sendMessage(page, prompt)) returns { ok: false } — the send button was not clickable, text injection failed, the composer was disabled (e.g. Claude at capacity or message queue full), the page navigated mid-send, or a send-button/textarea DOM change broke the send routine.
Common situations: Claude conversation is full or the model is overloaded so the send button is disabled; message length exceeds limits; Claude DOM update moving the send button; page reloaded between composer check and send; network hiccup during submission; rate limiting by Claude.
Related errors
- Unexpected Claude probe: ${JSON.stringify(result)}
- Claude whoami failed: ${result.detail}
- Codex send was not submitted.
- ${message}: malformed GeoGebra result
- Failed to detect GeoGebra applet: ${err?.message || err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/535a15b19380bee9.
Report an issue: GitHub.