jackwener/OpenCLI · error · CommandExecutionError

Send button not found

Error message

Send button not found

What it means

A CommandExecutionError thrown by the qoder send command after both send strategies fail: first clicking button[aria-label="Send message"] / button[title="Send message"] via clickFirstScript, then the clickByTextScript fallback with 'Send message' / 'Send' / '发送'. If neither finds a clickable send control, this error is thrown — the text may have been typed but never sent.

Source

Thrown at clis/qoder/quest.js:78

    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) }];
    },
});

// -------- ask --------
cli({
    site: 'qoder',
    name: 'ask',
    access: 'write',
    description: 'Send a prompt to Qoder and wait up to --timeout seconds for the reply (best-effort: polls for the chat turn count to grow + stabilize).',
    domain: 'localhost',
    strategy: Strategy.UI,
    browser: true,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry with a short wait after typing — the Send button only becomes enabled once the composer registers the injected text.
  2. Inspect the composer DOM and add the current selector (new aria-label or a form submit selector) to the clickFirstScript selector list.
  3. Add a keyboard fallback: dispatch an Enter keypress on the composer, which Qoder treats as send.
  4. Verify text injection succeeded first (composer value non-empty) since a disabled Send is usually a symptom of failed injection, not a missing button.

Example fix

// before
if (!textRes?.ok) throw new CommandExecutionError('Send button not found', '');
// after
if (!textRes?.ok) {
    const enterRes = await evaluateQoder(page, pressEnterInComposerScript());
    if (!enterRes?.ok) throw new CommandExecutionError('Send button not found', '');
}
Defensive patterns

Strategy: fallback

Validate before calling

// Verify injection registered and a send control exists before invoking
const state = await page.evaluate(() => {
  const el = document.querySelector('textarea, [contenteditable="true"]');
  const hasText = !!el && (el.value || el.innerText || '').trim().length > 0;
  const hasSend = !!document.querySelector('button[aria-label="Send message"], button[title="Send message"]');
  return { hasText, hasSend };
});
if (!state.hasText || !state.hasSend) throw new Error('Composer empty or Send control missing — send would fail');

Type guard

function hasClickResult(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('Send button not found')) {
    // keyboard fallback: focus composer and press Enter
    await focusComposerAndPressEnter();
  } else throw e;
}

Prevention

When it happens

Trigger: Running `qoder send <text>` when: the composer is empty in Qoder's eyes (injection silently failed or text was rejected), so the Send button is disabled/hidden; Qoder changed the aria-label/title (e.g. to 'Send' or an icon with different metadata); the send control is now an icon-only SVG button with no accessible label or text; or the UI is mid-render.

Common situations: Qoder redesigns replacing the labeled button with an icon-only button lacking aria-label; localized builds where text candidates ('Send message'/'Send'/'发送') don't match; Enter-to-send-only configurations with no visible button; automation racing the composer's enabled state after typing.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/3af66e24521c94c4. Report an issue: GitHub.