{"record":{"id":"c9bcd98a06f44468","repo":"jackwener/OpenCLI","slug":"twitter-likes-resume-file-filepath-count-does-n","errorCode":null,"errorMessage":"Twitter likes resume file ${filePath} count does not match its in-memory tweets","messagePattern":"Twitter likes resume file (.+?) count does not match its in-memory tweets","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/likes.js","lineNumber":149,"sourceCode":"    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,\n        outputFile,\n        updatedAt: parsed.updatedAt || null,\n    };\n}\n\n// Keep this in sync with twitter/bookmarks; wording is command-specific, so the\n// atomic tmp-write/rename cleanup sequence intentionally remains local.\nfunction writeResumeFile(filePath, payload) {","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/likes.js#L131-L167","documentation":"readResumeFile validates a Twitter likes resume file against the current in-memory execution state. When the command runs in in-memory mode (--no output file), the resume file must contain a 'tweets' array whose length equals the tweet count recorded in the saved state. If the array length differs from the recorded count, the resume state is internally inconsistent, so the CLI refuses to trust it and throws CommandExecutionError.","triggerScenarios":"Running `twitter likes --resume-file <path> --all` without --output-file, where the JSON in the resume file has a valid 'tweets' array but its parsed.tweets.length differs from the saved count field (e.g. the file was hand-edited, truncated, or written by a different version of the tool).","commonSituations":"Users manually trimming the tweets array in the resume JSON to shrink it; copying a resume file from another run whose count was recorded differently; a crash or partial write left the file with fewer tweets than the saved count.","solutions":["Regenerate the resume file by re-running `opencli twitter likes <user> --all --output-file <path> --resume-file <path>` from scratch instead of resuming.","Edit the resume file's 'count' field to equal the actual length of the 'tweets' array if you intentionally trimmed the tweets.","Restore the resume file from a backup taken before it was modified.","Verify in-memory mode is correct: if you meant to stream to disk, add --output-file so the tweets-array check is skipped."],"exampleFix":"// before (inconsistent resume JSON)\n{ \"count\": 150, \"tweets\": [ /* only 120 tweets */ ] }\n// after\n{ \"count\": 120, \"tweets\": [ /* the 120 tweets */ ] }","handlingStrategy":"validation","validationCode":"const state = JSON.parse(fs.readFileSync(resumePath, 'utf8'));\nif (!state.outputFile && Array.isArray(state.tweets) && state.tweets.length !== state.count) {\n  throw new Error(`Resume file inconsistent: tweets.length=${state.tweets.length} but count=${state.count}`);\n}","typeGuard":"function hasConsistentTweets(state) {\n  return typeof state.outputFile === 'string' && state.outputFile\n    || (Array.isArray(state.tweets) && state.tweets.length === state.count);\n}","tryCatchPattern":null,"preventionTips":["Never hand-edit the tweets array in a resume file; edit count together with it if you must.","Treat resume files as tool-managed artifacts — regenerate rather than repair.","Always pair in-memory resume checks with the same CLI version that wrote the file."],"tags":["twitter","resume-file","state-mismatch","cli"],"backgroundTag":"resume-state-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}