{"record":{"id":"56b1fff835ba8c6b","repo":"jackwener/OpenCLI","slug":"tweet-failed-to-post","errorCode":null,"errorMessage":"Tweet failed to post.","messagePattern":"Tweet failed to post\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/post.js","lineNumber":355,"sourceCode":"        }\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 } : {}),\n            ...(result.url ? { url: result.url } : {}),\n        }];\n    }\n});\n","sourceCodeStart":337,"sourceCodeEnd":366,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/post.js#L337-L366","documentation":"CommandExecutionError thrown when submitTweet explicitly reports failure ({ ok: false }) — unlike the unconfirmed timeout case, this is a definite failure and the message states nothing was posted, so retrying is safe.","triggerScenarios":"submitTweet resolves with result.ok falsy and no unconfirmed flag: the Post button click failed, X returned an error (duplicate post, empty tweet, rate limit, account restriction), or result is undefined/null.","commonSituations":"Tweeting text identical to a recent tweet (X duplicate detection); account temporarily limited from posting; X frontend changes breaking the submit flow; composer discarded the text.","solutions":["Read result?.message for X's specific reason (e.g. duplicate status, rate limit)","If duplicate content, edit the tweet text and retry","If rate-limited, wait and retry later","Open the composer in the browser and post manually to see X's on-page error","Check the account isn't locked/limited; verify the composer flow still works after X deploys"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// avoid X duplicate rejection before posting\nconst recent = await opencli('twitter tweets', { limit: 1 });\nif (recent?.[0]?.text === text) throw new Error('tweet text identical to last post');\nif (!text.trim()) throw new Error('tweet text is empty');","typeGuard":null,"tryCatchPattern":"try {\n  await postTweet({ text });\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && /failed to post/i.test(e.message)) {\n    console.error('Post definitively failed (nothing posted):', e.message);\n    // safe to fix the cause and retry\n  } else throw e;\n}","preventionTips":["Change text before re-posting similar content (X blocks duplicates)","Check account health/rate limits before automation runs","Never treat this error as ambiguous — nothing was posted, so retrying is safe","Read result.message for X's specific rejection reason"],"tags":["twitter","post-failure"],"backgroundTag":"tweet-post-rejected","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}