jackwener/OpenCLI · error · CommandExecutionError
composer type failed
Error message
composer type failed
What it means
A CommandExecutionError thrown by the qoder send command when the text-injection script (buildQoderInjectTextScript) fails to type the prompt into the composer. The message prefers the script's own reason (typeRes?.reason) and falls back to this literal string. It means DOM evaluation to fill the composer textarea returned ok:false — the send step is never reached.
Source
Thrown at clis/qoder/quest.js:67
cli({
site: 'qoder',
name: 'send',
access: 'write',
description: 'Type text into the Qoder composer and click "Send message" (fire-and-forget).',
domain: 'localhost',
strategy: Strategy.UI,
browser: true,
args: [
{ name: 'text', positional: true, required: true, help: 'Text to send' },
],
columns: ['Status', 'Length'],
func: async (page, kwargs) => {
const text = String(kwargs?.text || '').trim();
if (!text) throw new ArgumentError('text is required');
const beforeCount = await evaluateQoder(page, QODER_MESSAGE_COUNT_JS);
const typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text));
if (!typeRes?.ok) throw new CommandExecutionError(typeRes?.reason || 'composer type failed', '');
await page.wait(0.3);
// Click Send message
const sendRes = await evaluateQoder(page, clickFirstScript([
'button[aria-label="Send message"]',
'button[title="Send message"]',
]));
if (!sendRes?.ok) {
// Fallback: try clickByText.
const textRes = await evaluateQoder(page, clickByTextScript(['Send message', 'Send', '发送']));
if (!textRes?.ok) throw new CommandExecutionError('Send button not found', '');
}
const afterCount = await waitForMessageCountGrowth(page, beforeCount);
if (Number(afterCount) <= Number(beforeCount)) {
throw new CommandExecutionError('Qoder send did not create a new visible message row');
}
return [{ Status: 'sent', Length: String(text.length) }];
},View on GitHub (pinned to 49907e53dc)
Solutions
- Confirm the Qoder chat view is open and the composer is visible before running send; retry after a short wait.
- If the reason indicates a selector miss, inspect the composer DOM and update buildQoderInjectTextScript's selector to match the current markup.
- If the value set is reverted (React controlled input), switch the injection to input-event-based methods: document.execCommand('insertText') or native setter + dispatched InputEvent.
- Re-attach to the correct webview/window (close extra Qoder windows) and rerun.
Example fix
// before const typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text)); if (!typeRes?.ok) throw new CommandExecutionError(typeRes?.reason || 'composer type failed', ''); // after await page.wait(1); // ensure composer mounted let typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text)); if (!typeRes?.ok) typeRes = await evaluateQoder(page, insertTextViaExecCommandScript(text)); // contenteditable fallback
Defensive patterns
Strategy: retry
Validate before calling
// Confirm the composer exists and is editable before invoking send
const composerReady = await page.evaluate(() => {
const el = document.querySelector('textarea, [contenteditable="true"]');
return !!el && !el.disabled && !el.readOnly;
});
if (!composerReady) throw new Error('Qoder composer not ready — wait for the chat view to mount'); Type guard
function injectionSucceeded(res) {
return typeof res === 'object' && res !== null && res.ok === true;
} Try / catch
try {
await runCli('qoder send', [text]);
} catch (e) {
if (String(e.message).includes('composer type failed')) {
await sleep(1000);
await runCli('qoder send', [text]); // retry after composer mounts
} else throw e;
} Prevention
- Wait for the chat view/composer to be visible before sending.
- After Qoder updates, re-test text injection — editor internals may change.
- Keep only one Qoder window open so evaluate targets the right frame.
- Prefer event-based injection (execCommand/insertText) for contenteditable composers.
When it happens
Trigger: Running `qoder send <text>` when: the composer textarea/input does not exist yet (UI still loading or wrong panel active); the injection script targeted a selector Qoder changed in an update; the webview is in a state where execCommand/insertText or setting .value + dispatching input events is blocked (React controlled components resetting value); or evaluateQoder could not attach to the page.
Common situations: Qoder updates switching the composer from a plain textarea to a contenteditable/ProseMirror editor, breaking value-based injection; sending before the chat view finishes mounting; multiple Qoder windows causing evaluateQoder to target a stale frame.
Related errors
- Prompt Enhance button not found
- Open Editor button not found
- New Quest button not found
- Send button not found
- Qoder send did not create a new visible message row
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/35aad8c3c9b974ee.
Report an issue: GitHub.