jackwener/OpenCLI · error · ArgumentError
--output-file requires --resume-file so partial archives rem
Error message
--output-file requires --resume-file so partial archives remain resumable
What it means
When archiving to a JSONL output file, a matching --resume-file is mandatory so a partially written archive can be continued. clis/twitter/bookmarks.js:202 throws ArgumentError when --output-file is given without --resume-file. Without resume state, an interrupted run would leave an unresumable partial archive.
Source
Thrown at clis/twitter/bookmarks.js:202
func: async (page, kwargs) => {
const fetchAll = Boolean(kwargs.all);
const limit = fetchAll ? Number.POSITIVE_INFINITY : (kwargs.limit || 20);
const resumeFile = resolveOptionalFilePath(kwargs['resume-file'], '--resume-file');
const outputFile = resolveOptionalFilePath(kwargs['output-file'], '--output-file');
const useOutputFile = Boolean(fetchAll && outputFile);
const maxPages = resolveMaxPages(kwargs, fetchAll);
const topByEngagement = Number(kwargs['top-by-engagement'] || 0);
if (useOutputFile && topByEngagement > 0) {
throw new ArgumentError('--top-by-engagement cannot be combined with --output-file');
}
if (outputFile && !fetchAll) {
throw new ArgumentError('--output-file requires --all');
}
if (resumeFile && !fetchAll) {
throw new ArgumentError('--resume-file requires --all');
}
if (outputFile && !resumeFile) {
throw new ArgumentError('--output-file requires --resume-file so partial archives remain resumable');
}
const cookies = await page.getCookies({ url: 'https://x.com' });
const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;
if (!ct0)
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
const queryId = await resolveTwitterQueryId(page, 'Bookmarks', BOOKMARKS_QUERY_ID);
const headers = JSON.stringify({
'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
'X-Csrf-Token': ct0,
'X-Twitter-Auth-Type': 'OAuth2Session',
'X-Twitter-Active-User': 'yes',
});
const resumed = fetchAll ? readResumeFile(resumeFile, {
source: 'bookmarks',
outputFile: useOutputFile ? outputFile : null,
}) : null;
if (useOutputFile && resumed && resumed.count > 0 && !fs.existsSync(outputFile)) {
throw new CommandExecutionError(`Twitter bookmarks output file is missing for resume state: ${outputFile}`);View on GitHub (pinned to 49907e53dc)
Solutions
- Add --resume-file pointing to the state file (e.g. archive.resume.json) alongside --output-file.
- Remove --output-file if you want an in-memory fetch that tolerates interruption via the resume file alone.
- Wrap both flags in a single script/alias so they are never separated.
Example fix
// before twitter bookmarks --all --output-file bookmarks.jsonl // after twitter bookmarks --all --output-file bookmarks.jsonl --resume-file bookmarks.resume.json
Defensive patterns
Strategy: validation
Validate before calling
if (has('--output-file') && !has('--resume-file')) {
throw new Error('--output-file requires --resume-file so partial archives remain resumable');
} Type guard
function canArchiveToOutput(opts) {
return typeof opts.outputFile === 'string' && typeof opts.resumeFile === 'string';
} Try / catch
try {
await runBookmarks(argv);
} catch (e) {
if (e instanceof ArgumentError && e.message.includes('requires --resume-file')) {
console.error('Add --resume-file <state.json> alongside --output-file.');
process.exitCode = 2;
} else throw e;
} Prevention
- Treat --output-file and --resume-file as an atomic flag pair in scripts.
- Centralize archive invocations in one helper that always emits both flags.
- Document the pairing requirement in team runbooks.
When it happens
Trigger: Running `twitter bookmarks --all --output-file archive.jsonl` without `--resume-file`. Pure flag check in the argument validation block, before cookies/network access.
Common situations: Users adding --output-file to an existing command line but omitting --resume-file; automations that build flags conditionally and skip the resume flag; misunderstanding that output-file alone is sufficient for archiving.
Related errors
- <train-no> "${trainNo}" does not look like a 12306 internal
- --from station must not be empty
- --to station must not be empty
- --seat-types must contain only 12306 seat letters/digits (A-
- --from and --to must differ; both resolved to ${fromStation.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/89c26de97ae53fc7.
Report an issue: GitHub.