{"record":{"id":"212121966fc2aacf","repo":"jackwener/OpenCLI","slug":"could-not-parse-twitter-likes-resume-file-filepa","errorCode":null,"errorMessage":"Could not parse Twitter likes resume file ${filePath}: ${error instanceof Error ? error.message : String(error)}","messagePattern":"Could not parse Twitter likes resume file (.+?): (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/likes.js","lineNumber":128,"sourceCode":"            }\n            for (const item of content?.items || []) {\n                const nested = extractLikedTweet(item.item?.itemContent?.tweet_results?.result, seen);\n                if (nested)\n                    tweets.push(nested);\n            }\n        }\n    }\n    return { tweets, nextCursor };\n}\nfunction readResumeFile(filePath, expected = null) {\n    if (!filePath || !fs.existsSync(filePath))\n        return null;\n    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))","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/likes.js#L110-L146","documentation":"readResumeFile in the twitter likes CLI throws this CommandExecutionError when the resume file exists but its contents are not valid JSON (fs.readFileSync succeeded, JSON.parse failed). The error includes the file path and the underlying parse message so the developer knows which artifact is corrupt.","triggerScenarios":"Calling the `twitter likes` command in resume mode (e.g. `--resume <file>`) where the file at filePath exists but contains malformed JSON — truncated writes, manual edits, empty file, or non-JSON content.","commonSituations":"A previous run was killed mid-write leaving a truncated resume file; the file was edited by hand with trailing commas/comments; the file was overwritten by another tool; resuming against a file from a different format/version of the library.","solutions":["Inspect the file at filePath and fix the JSON syntax (validate with a JSON linter)","Delete the corrupt resume file and restart the likes run from scratch","Re-create the resume file from a known-good backup","Ensure the process writing the resume file completes atomically (write to temp then rename) in your wrapper"],"exampleFix":"// before (truncated/corrupt resume.json)\n{\"count\": 42, \"cursor\": \"abc\n// after\n{\"count\": 42, \"cursor\": \"abc\", \"source\": \"likes\", \"username\": \"someuser\"}","handlingStrategy":"validation","validationCode":"function canParseResumeFile(filePath) {\n  try { JSON.parse(fs.readFileSync(filePath, 'utf8')); return true; }\n  catch { return false; }\n}\n// resume only if canParseResumeFile(resumePath)","typeGuard":null,"tryCatchPattern":"try {\n  await runLikes({ resume: resumePath });\n} catch (e) {\n  if (/Could not parse Twitter likes resume file/.test(e.message)) {\n    fs.rmSync(resumePath); // or restore a backup, then restart fresh\n    return runLikes({});\n  }\n  throw e;\n}","preventionTips":["Validate resume files with a JSON parser before passing --resume","Write resume files atomically (temp file + rename) if wrapping the CLI","Don't hand-edit resume files; let the library generate them","Keep backups of resume files before long runs"],"tags":["twitter","resume-file","json-parse","validation"],"backgroundTag":"resume-file-corrupt","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}