{"record":{"id":"feb0a971fa621a7f","repo":"jackwener/OpenCLI","slug":"could-not-type-tweet-text","errorCode":null,"errorMessage":"Could not type tweet text.","messagePattern":"Could not type tweet text\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/post.js","lineNumber":343,"sourceCode":"                    if (!isRecoverableFileInputError(err)) {\n                        throw err;\n                    }\n                    await attachImagesViaDataTransfer(page, absPaths);\n                }\n            } else {\n                await attachImagesViaDataTransfer(page, absPaths);\n            }\n            const uploadState = await waitForImageUpload(page, absPaths.length);\n            if (!uploadState?.ok) {\n                throw new TimeoutError('twitter image upload', UPLOAD_TIMEOUT_MS / 1000, 'Nothing was posted. Retry, or attach a smaller image.');\n            }\n        }\n\n        // Insert and verify the text after media upload so text + images are in\n        // the final Draft.js composer state immediately before clicking Post.\n        const typeResult = await insertComposerText(page, text);\n        if (!typeResult?.ok) {\n            throw new CommandExecutionError(typeResult?.message ?? 'Could not type tweet text.', 'Open the composer in the browser and check whether X is asking you to log in.');\n        }\n\n        await page.wait(1);\n        const result = await submitTweet(page, text);\n        if (result?.unconfirmed) {\n            // The poll expiring does not mean the tweet stayed in the composer,\n            // so this must not read as a definite failure: the agent workflow\n            // retries CommandExecutionError and would post twice (#2255).\n            throw new TimeoutError('twitter post', SUBMIT_TIMEOUT_MS / 1000, `${result.message} Check \\`opencli twitter tweets --limit 1\\` before retrying; the post may already be live.`);\n        }\n        if (!result?.ok) {\n            throw new CommandExecutionError(result?.message ?? 'Tweet failed to post.', 'Nothing was posted. Open the composer in the browser and retry.');\n        }\n        return [{\n            status: 'success',\n            message: result.message,\n            text,\n            ...(result.id ? { id: result.id } : {}),","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/post.js#L325-L361","documentation":"CommandExecutionError thrown when insertComposerText cannot type/verify the tweet text in the Draft.js composer. The hint tells the user to open the composer in the browser and check whether X is asking them to log in, because the most common cause is a lost session.","triggerScenarios":"insertComposerText(page, text) returns { ok: false } — the textarea never accepts input or the typed text is not reflected in the composer state — typically because X rendered a login wall or the editor selector changed.","commonSituations":"Expired X session cookies mid-run; X showing an age/account-verification interstitial; rate limiting that soft-blocks posting; the composer DOM changing after an X frontend deploy.","solutions":["Open the browser session and confirm you are logged into X (the error's own suggestion); re-authenticate if needed","Retry once — a transient login wall often clears after a fresh page.goto","Check whether X is showing an interstitial (verification, suspension, ToS notice) on the account","If it persists after re-login, the composer DOM may have changed; update or report the insertComposerText selectors"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await postTweet({ text });\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && /type tweet text/i.test(e.message)) {\n    await relogin();            // session likely expired\n    return postTweet({ text });\n  }\n  throw e;\n}","preventionTips":["Refresh the X session (opencli login) before long automation runs","Detect login walls early by checking x.com/home before posting","Keep text non-empty and free of characters that break Draft.js insertion","Handle one transient retry, then surface the error for human review"],"tags":["twitter","auth","dom"],"backgroundTag":"twitter-session-expired","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}