{"record":{"id":"cd2af48a4936ee3a","repo":"jackwener/OpenCLI","slug":"twitter-bookmarks-resume-file-filepath-is-missi","errorCode":null,"errorMessage":"Twitter bookmarks resume file ${filePath} is missing in-memory tweets","messagePattern":"Twitter bookmarks resume file (.+?) is missing in-memory tweets","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/bookmarks.js","lineNumber":130,"sourceCode":"    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    };\n}\n\n// Keep this in sync with twitter/likes; wording is command-specific, so the\n// atomic tmp-write/rename cleanup sequence intentionally remains local.","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/bookmarks.js#L112-L148","documentation":"In-memory mode (no --output-file) stores the fetched tweets inside the resume file itself. If expected.outputFile is null but the resume file lacks a `tweets` array, readResumeFile throws this CommandExecutionError because there is no archive and no stored tweets to continue from.","triggerScenarios":"Resuming an in-memory --all run whose resume file has `tweets` removed or renamed (manual edit), or resuming with an outputFile-crafted file while running without --output-file.","commonSituations":"Cleaning up the resume file to shrink it and deleting `tweets`; a schema change between library versions; mixing files produced with different flags.","solutions":["Delete the resume file and restart the --all sync (in-memory state cannot be reconstructed without tweets).","Re-run with --output-file --resume-file so partial data lives in the JSONL archive instead.","Restore `tweets` from a backup if the original array is available."],"exampleFix":"// before: resume.json = {\"count\": 5, \"cursor\": \"X\", \"source\": \"bookmarks\"}  (no tweets)\n// after: add back or restart\ncli twitter bookmarks --all --resume-file ./b.json --output-file ./archive.jsonl","handlingStrategy":"validation","validationCode":"const parsed = JSON.parse(fs.readFileSync(resumeFile, 'utf8'));\nif (!parsed.outputFile && !Array.isArray(parsed.tweets)) {\n  // in-memory resume state unusable: start fresh or switch to archive mode\n  fs.rmSync(resumeFile, { force: true });\n}","typeGuard":"function hasInMemoryTweets(v) {\n  return typeof v === 'object' && v !== null && Array.isArray(v.tweets);\n}","tryCatchPattern":"try {\n  await run(args);\n} catch (e) {\n  if (String(e.message).includes('is missing in-memory tweets')) {\n    fs.rmSync(resumeFile, { force: true });\n    await run(args); // restart clean\n  } else throw e;\n}","preventionTips":["Do not strip the `tweets` array from in-memory resume files.","For long syncs use --output-file --resume-file so data lives in the archive.","Never truncate the resume file to save space.","Regenerate rather than repair untrusted resume files."],"tags":["resume-file","in-memory","cli"],"backgroundTag":"resume-file-missing-tweets","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}