{"record":{"id":"6d5d621eb000a21d","repo":"jackwener/OpenCLI","slug":"qoder-send-did-not-create-a-new-visible-message-ro","errorCode":null,"errorMessage":"Qoder send did not create a new visible message row","messagePattern":"Qoder send did not create a new visible message row","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/qoder/quest.js","lineNumber":82,"sourceCode":"\n        const beforeCount = await evaluateQoder(page, QODER_MESSAGE_COUNT_JS);\n        const typeRes = await evaluateQoder(page, buildQoderInjectTextScript(text));\n        if (!typeRes?.ok) throw new CommandExecutionError(typeRes?.reason || 'composer type failed', '');\n        await page.wait(0.3);\n\n        // Click Send message\n        const sendRes = await evaluateQoder(page, clickFirstScript([\n            'button[aria-label=\"Send message\"]',\n            'button[title=\"Send message\"]',\n        ]));\n        if (!sendRes?.ok) {\n            // Fallback: try clickByText.\n            const textRes = await evaluateQoder(page, clickByTextScript(['Send message', 'Send', '发送']));\n            if (!textRes?.ok) throw new CommandExecutionError('Send button not found', '');\n        }\n        const afterCount = await waitForMessageCountGrowth(page, beforeCount);\n        if (Number(afterCount) <= Number(beforeCount)) {\n            throw new CommandExecutionError('Qoder send did not create a new visible message row');\n        }\n        return [{ Status: 'sent', Length: String(text.length) }];\n    },\n});\n\n// -------- ask --------\ncli({\n    site: 'qoder',\n    name: 'ask',\n    access: 'write',\n    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).',\n    domain: 'localhost',\n    strategy: Strategy.UI,\n    browser: true,\n    args: [\n        { name: 'text', positional: true, required: true, help: 'Prompt text' },\n        { name: 'timeout', type: 'int', required: false, default: 120, help: 'Max seconds to wait' },\n    ],","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/qoder/quest.js#L64-L100","documentation":"A CommandExecutionError thrown by qoder send as a post-send verification failure. After clicking Send (both strategies), waitForMessageCountGrowth polls QODER_MESSAGE_COUNT_JS for up to 5s; if the visible message-row count never exceeds the pre-send count, the command concludes the message never appeared and throws. This is the safety net that catches 'clicked send but nothing was actually sent'.","triggerScenarios":"Running `qoder send <text>` when: the send click landed on a disabled button (injection never registered); Qoder treats the injected text as empty and ignores Enter/click; QODER_MESSAGE_COUNT_JS's row selector no longer matches the message list after an update, so growth is invisible; the message was sent into a different Quest/window than the one being counted; or generation errors client-side so no user row renders.","commonSituations":"Qoder updates renaming message-row classes, breaking the count selector and producing false negatives even though sending worked; rate limits or network errors preventing message creation; automated sends racing the composer's enabled state; multiple open Qoder windows causing count/verify to run in different frames.","solutions":["Open Qoder and visually confirm whether the message actually appeared — if it did, the count selector in QODER_MESSAGE_COUNT_JS is stale; update it to the current message-list markup.","Increase the 5s wait window (timeoutMs in waitForMessageCountGrowth) for slow/large messages.","Ensure text injection truly registered (check composer empties on send) before clicking Send; re-inject if the composer still holds text.","Close extra Qoder windows and verify evaluateQoder targets the same frame for counting and sending."],"exampleFix":"// before\nconst afterCount = await waitForMessageCountGrowth(page, beforeCount);\nif (Number(afterCount) <= Number(beforeCount)) {\n    throw new CommandExecutionError('Qoder send did not create a new visible message row');\n}\n// after\nconst afterCount = await waitForMessageCountGrowth(page, beforeCount, 15000); // longer window\nif (Number(afterCount) <= Number(beforeCount)) {\n    throw new CommandExecutionError('Qoder send did not create a new visible message row');\n}","handlingStrategy":"retry","validationCode":"// Sanity-check the message-count selector still matches before relying on send verification\nconst count = await page.evaluate(() => QODER_MESSAGE_COUNT_JS);\nif (count === null || Number.isNaN(Number(count))) throw new Error('Message-count selector stale — update QODER_MESSAGE_COUNT_JS');","typeGuard":"function countGrew(before, after) {\n  const b = Number(before), a = Number(after);\n  return Number.isFinite(b) && Number.isFinite(a) && a > b;\n}","tryCatchPattern":"try {\n  await runCli('qoder send', [text]);\n} catch (e) {\n  if (String(e.message).includes('did not create a new visible message row')) {\n    await sleep(3000);\n    await runCli('qoder send', [text]); // one retry; if it recurs, check Qoder UI manually\n  } else throw e;\n}","preventionTips":["Check the Qoder UI once after this error — a false negative means the count selector is stale.","Allow longer wait windows for slow networks before declaring failure.","Send into one focused Quest/window; avoid multiple Qoder instances.","Re-validate QODER_MESSAGE_COUNT_JS after each Qoder version bump."],"tags":["ui-automation","verification","browser","qoder"],"backgroundTag":"action-effect-not-confirmed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}