{"record":{"id":"9206017fa93491f5","repo":"jackwener/OpenCLI","slug":"resume-file-source-mismatch-expected-expected-s-920601","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/likes.js","lineNumber":141,"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 likes 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 likes 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 (String(parsed.username || '').toLowerCase() !== String(expected.username).toLowerCase())\n            throw new ArgumentError(`Resume file username mismatch: expected @${expected.username}, found @${parsed.username || '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 likes resume file ${filePath} is missing in-memory tweets`);\n        if (!expected.outputFile && parsed.tweets.length !== count)\n            throw new CommandExecutionError(`Twitter likes resume file ${filePath} count does not match its in-memory tweets`);\n        if (parsed.complete)\n            throw new CommandExecutionError(`Twitter likes resume file ${filePath} is already marked complete`);\n    }\n    return {\n        cursor,\n        count,\n        tweets: Array.isArray(parsed.tweets) ? parsed.tweets : [],\n        username: parsed.username || null,\n        complete: Boolean(parsed.complete),\n        source: parsed.source || null,","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/likes.js#L123-L159","documentation":"When an `expected` descriptor is supplied, readResumeFile checks that the resume file's `source` field matches the current run's source and throws this ArgumentError on mismatch. This prevents resuming a likes run from a file produced by a different collection source (which would produce inconsistent cursors/results).","triggerScenarios":"Running `twitter likes` with --resume plus matching expectations where parsed.source differs from expected.source — e.g. resuming a file generated for a different source type (likes vs another timeline source) or from an older/newer CLI variant that wrote a different source label.","commonSituations":"Reusing one resume file across different commands or source types; a library upgrade renamed/changed the source identifier; copy-pasting a resume file from a colleague's run that used a different source option.","solutions":["Check the file's `source` field and either run with the source it was created for, or regenerate the resume file with the intended source","Delete the mismatched resume file and start a fresh run","Pin/align the library version between the run that created the file and the resuming run","If the source label is legitimately the same, fix a corrupted `source` field manually before resuming"],"exampleFix":"// before (mismatch)\n{\"source\": \"favorites\", ...}   // resuming a \"likes\" run\n// after\n{\"source\": \"likes\", ...}       // or start a fresh likes run","handlingStrategy":"validation","validationCode":"const parsed = JSON.parse(fs.readFileSync(resumePath, 'utf8'));\nif (parsed.source !== expectedSource) throw new Error(`source mismatch: ${parsed.source} != ${expectedSource}`);","typeGuard":null,"tryCatchPattern":"try {\n  await runLikes({ resume: resumePath, source: expectedSource });\n} catch (e) {\n  if (/Resume file source mismatch/.test(e.message)) {\n    // regenerate a resume file for this source or run with the file's original source\n  }\n  throw e;\n}","preventionTips":["Use one resume file per source type; never share across commands","Keep (source, username) in resume filenames","Align library versions between creating and resuming runs","Inspect the file's `source` field before resuming"],"tags":["twitter","resume-file","argument-error","mismatch"],"backgroundTag":"resume-file-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}