{"record":{"id":"9280cda51cbffae1","repo":"jackwener/OpenCLI","slug":"browser-session-required-for-twitter-reply-dm","errorCode":null,"errorMessage":"Browser session required for twitter reply-dm","messagePattern":"Browser session required for twitter reply-dm","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/reply-dm.js","lineNumber":20,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\ncli({\n    site: 'twitter',\n    name: 'reply-dm',\n    access: 'write',\n    description: 'Send a message to recent DM conversations',\n    domain: 'x.com',\n    strategy: Strategy.UI,\n    browser: true,\n    args: [\n        { name: 'text', type: 'string', required: true, positional: true, help: 'Message text to send (e.g. \"我的微信 wxkabi\")' },\n        { name: 'max', type: 'int', required: false, default: 20, help: 'Maximum number of conversations to reply to (default: 20)' },\n        { name: 'skip-replied', type: 'boolean', required: false, default: true, help: 'Skip conversations where you already sent the same text (default: true)' },\n        { name: 'timeout', type: 'int', required: false, default: 600, help: 'Max seconds for the overall command (default: 600 — batch op)' },\n    ],\n    columns: ['index', 'status', 'user', 'message'],\n    func: async (page, kwargs) => {\n        if (!page)\n            throw new CommandExecutionError('Browser session required for twitter reply-dm');\n        const messageText = kwargs.text;\n        const maxSend = kwargs.max ?? 20;\n        const skipReplied = kwargs['skip-replied'] !== false;\n        const results = [];\n        let sentCount = 0;\n        // Step 1: Navigate to messages to get conversation list\n        await page.goto('https://x.com/messages');\n        await page.wait({ selector: '[data-testid=\"primaryColumn\"]' });\n        // Step 2: Collect conversations with scroll-to-load\n        const needed = maxSend + 10; // extra buffer for skips\n        const convList = await page.evaluate(`(async () => {\n      try {\n        // Wait for initial items\n        let attempts = 0;\n        while (attempts < 10) {\n          const items = document.querySelectorAll('[data-testid^=\"dm-conversation-item-\"], [data-testid=\"conversation\"]');\n          if (items.length > 0) break;\n          await new Promise(r => setTimeout(r, 1000));","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/reply-dm.js#L2-L38","documentation":"CommandExecutionError thrown at the start of the twitter reply-dm command when the `page` argument is falsy — the batch DM-reply operation requires an active browser session and cannot enumerate conversations without one.","triggerScenarios":"Running 'twitter reply-dm' without an open browser session, so func receives page === undefined/null, before any navigation to the messages page.","commonSituations":"Scheduling the batch job without a browser bootstrap step; the browser crashed earlier in the pipeline; running the command from a script that never calls the session open command; session timed out and closed before this command.","solutions":["Open/start the browser session before running twitter reply-dm","In batch scripts, assert the session is alive before each command and reopen if closed","Catch CommandExecutionError with the 'Browser session required' message and restart the browser then rerun","Avoid long gaps between session start and command execution so the session does not close"],"exampleFix":"// before\nawait cli.run('twitter reply-dm', { text: 'thanks!' });\n// after\nawait cli.run('browser open');\nawait cli.run('twitter reply-dm', { text: 'thanks!' });","handlingStrategy":"validation","validationCode":"if (!browserSession || !browserSession.page) {\n  await cli.run('browser open');\n}","typeGuard":"function hasLivePage(page) {\n  return page != null && typeof page.evaluate === 'function' && typeof page.goto === 'function';\n}","tryCatchPattern":"try {\n  await cli.run('twitter reply-dm', kwargs);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /Browser session required/.test(e.message)) {\n    await cli.run('browser open');\n    return cli.run('twitter reply-dm', kwargs);\n  }\n  throw e;\n}","preventionTips":["Open the browser session before scheduled batch DM jobs","Re-assert session liveness before each long-running batch step","Keep batch durations within session lifetime or reopen periodically","Handle session crashes from earlier steps instead of assuming continuity"],"tags":["browser-session","prerequisite","batch-operation"],"backgroundTag":"missing-browser-session","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}