{"record":{"id":"b5b6ed3165246092","repo":"jackwener/OpenCLI","slug":"resume-file-requires-all","errorCode":null,"errorMessage":"--resume-file requires --all","messagePattern":"--resume-file requires --all","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/bookmarks.js","lineNumber":199,"sourceCode":"        { name: 'top-by-engagement', type: 'int', default: 0, help: 'When set to N>0, re-rank the bookmarks by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the API\\'s native (saved-time) ordering. Incompatible with --output-file.' },\n    ],\n    columns: ['id', 'author', 'text', 'likes', 'retweets', 'bookmarks', 'created_at', 'url', 'has_media', 'media_urls', 'media_posters'],\n    func: async (page, kwargs) => {\n        const fetchAll = Boolean(kwargs.all);\n        const limit = fetchAll ? Number.POSITIVE_INFINITY : (kwargs.limit || 20);\n        const resumeFile = resolveOptionalFilePath(kwargs['resume-file'], '--resume-file');\n        const outputFile = resolveOptionalFilePath(kwargs['output-file'], '--output-file');\n        const useOutputFile = Boolean(fetchAll && outputFile);\n        const maxPages = resolveMaxPages(kwargs, fetchAll);\n        const topByEngagement = Number(kwargs['top-by-engagement'] || 0);\n        if (useOutputFile && topByEngagement > 0) {\n            throw new ArgumentError('--top-by-engagement cannot be combined with --output-file');\n        }\n        if (outputFile && !fetchAll) {\n            throw new ArgumentError('--output-file requires --all');\n        }\n        if (resumeFile && !fetchAll) {\n            throw new ArgumentError('--resume-file requires --all');\n        }\n        if (outputFile && !resumeFile) {\n            throw new ArgumentError('--output-file requires --resume-file so partial archives remain resumable');\n        }\n        const cookies = await page.getCookies({ url: 'https://x.com' });\n        const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;\n        if (!ct0)\n            throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');\n        const queryId = await resolveTwitterQueryId(page, 'Bookmarks', BOOKMARKS_QUERY_ID);\n        const headers = JSON.stringify({\n            'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,\n            'X-Csrf-Token': ct0,\n            'X-Twitter-Auth-Type': 'OAuth2Session',\n            'X-Twitter-Active-User': 'yes',\n        });\n        const resumed = fetchAll ? readResumeFile(resumeFile, {\n            source: 'bookmarks',\n            outputFile: useOutputFile ? outputFile : null,","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/bookmarks.js#L181-L217","documentation":"The twitter bookmarks CLI requires --resume-file to be paired with --all because resume state (cursor, counts) is only meaningful for a full-archive run. Argument validation at clis/twitter/bookmarks.js:199 throws ArgumentError when a resume file is given but --all is absent. This prevents partial (--limit style) fetches from silently ignoring or corrupting resume state.","triggerScenarios":"Running `twitter bookmarks --resume-file <path>` without `--all`. The check is `if (resumeFile && !fetchAll)` in the command's argument validation block, executed before any network calls.","commonSituations":"Users continuing a previously interrupted full archive forget to re-add --all; shell aliases or scripts that hardcode --resume-file for every invocation; documentation examples copied incompletely.","solutions":["Add --all to the command so the fetch runs in full-archive mode where resume files apply.","Drop --resume-file if you only want a partial fetch; resume state only applies to full archives.","Update wrapper scripts/aliases to always pass --all and --resume-file together."],"exampleFix":"// before\ntwitter bookmarks --resume-file ./resume.json\n// after\ntwitter bookmarks --all --resume-file ./resume.json","handlingStrategy":"validation","validationCode":"const args = process.argv.slice(2);\nconst has = (f) => args.includes(f);\nif (has('--resume-file') && !has('--all')) {\n  throw new Error('--resume-file requires --all');\n}","typeGuard":"function isFullArchiveResume(opts) {\n  return typeof opts.resumeFile === 'string' && opts.resumeFile.length > 0 && opts.fetchAll === true;\n}","tryCatchPattern":"try {\n  await runBookmarks(argv);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('--resume-file requires --all')) {\n    console.error('Usage: twitter bookmarks --all --resume-file <path>');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Always pass --all and --resume-file as a pair; wrap them in one script or alias.","Validate flag combinations in your wrapper before invoking the CLI.","Read the CLI usage/help output before composing flag sets."],"tags":["cli","argument-validation","twitter"],"backgroundTag":"incompatible-cli-flags","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}