{"record":{"id":"9e30deb04ba7aa0d","repo":"jackwener/OpenCLI","slug":"resume-file-source-mismatch-expected-expected-s","errorCode":null,"errorMessage":"Resume file source mismatch: expected ${expected.source}, found ${parsed.source || 'unknown'}","messagePattern":"Resume file source mismatch: expected (.+?), found (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/bookmarks.js","lineNumber":126,"sourceCode":"    let parsed;\n    try {\n        parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));\n    }\n    catch (error) {\n        throw new CommandExecutionError(`Could not parse Twitter bookmarks resume file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);\n    }\n    const count = parsed?.count;\n    const cursor = parsed?.cursor == null ? null : String(parsed.cursor);\n    const outputFile = parsed?.outputFile ? path.resolve(String(parsed.outputFile)) : null;\n    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)\n        || !Number.isInteger(count) || count < 0\n        || (parsed.cursor != null && typeof parsed.cursor !== 'string')\n        || (cursor !== null && !cursor.trim())) {\n        throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} has an invalid shape`);\n    }\n    if (expected) {\n        if (parsed.source !== expected.source)\n            throw new ArgumentError(`Resume file source mismatch: expected ${expected.source}, found ${parsed.source || 'unknown'}`);\n        if (outputFile !== expected.outputFile)\n            throw new ArgumentError(`Resume file output mismatch: expected ${expected.outputFile || 'in-memory mode'}, found ${outputFile || 'in-memory mode'}`);\n        if (!expected.outputFile && !Array.isArray(parsed.tweets))\n            throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} is missing in-memory tweets`);\n        if (!expected.outputFile && parsed.tweets.length !== count)\n            throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} count does not match its in-memory tweets`);\n        if (parsed.complete)\n            throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} is already marked complete`);\n    }\n    return {\n        cursor,\n        count,\n        tweets: Array.isArray(parsed.tweets) ? parsed.tweets : [],\n        complete: Boolean(parsed.complete),\n        source: parsed.source || null,\n        outputFile,\n        updatedAt: parsed.updatedAt || null,\n    };","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/bookmarks.js#L108-L144","documentation":"When resuming, the `expected` object built by the command carries source: 'bookmarks'. If the resume file's `source` field differs (or is missing), readResumeFile throws this ArgumentError to prevent applying another command's saved state (e.g. likes) to a bookmarks sync.","triggerScenarios":"Running `twitter bookmarks --all --resume-file <path>` where the file was created by `twitter likes --resume-file <same path>` or another source, or the file's `source` field was deleted in a manual edit.","commonSituations":"Sharing one resume file path between likes and bookmarks syncs; copying a resume file across commands; stripping fields while reformatting the JSON.","solutions":["Use a dedicated resume-file path per command (one for bookmarks, one for likes).","Delete the mismatched file and start a fresh bookmarks sync.","If the file is otherwise correct, set `\"source\": \"bookmarks\"` (only if you are certain of its origin)."],"exampleFix":"// before: resume.json = {\"source\": \"likes\", ...}\ncli twitter likes --all --resume-file ./likes.json   # run with the matching command\n// after: bookmarks uses its own file\ncli twitter bookmarks --all --resume-file ./bookmarks.json","handlingStrategy":"validation","validationCode":"const parsed = JSON.parse(fs.readFileSync(resumeFile, 'utf8'));\nif (parsed.source !== 'bookmarks') throw new Error('wrong source, use the matching command');","typeGuard":"function isBookmarksResume(v) {\n  return typeof v === 'object' && v !== null && v.source === 'bookmarks';\n}","tryCatchPattern":"try {\n  await run(['twitter', 'bookmarks', '--all', '--resume-file', p]);\n} catch (e) {\n  if (String(e.message).includes('Resume file source mismatch')) {\n    // use a per-command resume path\n    await run(['twitter', 'bookmarks', '--all', '--resume-file', 'bookmarks-resume.json']);\n  } else throw e;\n}","preventionTips":["Use a distinct resume-file path per command (bookmarks vs likes).","Never copy resume files between commands.","Check the `source` field before resuming.","Name files after the command: bookmarks-resume.json."],"tags":["argument-error","resume-file","mismatch"],"backgroundTag":"resume-file-source-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}