{"record":{"id":"76aff50b230be529","repo":"jackwener/OpenCLI","slug":"could-not-persist-twitter-likes-resume-state-er","errorCode":null,"errorMessage":"Could not persist Twitter likes resume state: ${error instanceof Error ? error.message : String(error)}","messagePattern":"Could not persist Twitter likes resume state: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/likes.js","lineNumber":182,"sourceCode":"\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) {\n    if (!filePath)\n        return;\n    ensureParentDir(filePath);\n    const temporaryPath = `${filePath}.tmp-${process.pid}`;\n    try {\n        fs.writeFileSync(temporaryPath, JSON.stringify(payload, null, 2) + '\\n');\n        fs.renameSync(temporaryPath, filePath);\n    }\n    catch (error) {\n        try {\n            fs.rmSync(temporaryPath, { force: true });\n        }\n        catch {\n        }\n        throw new CommandExecutionError(`Could not persist Twitter likes resume state: ${error instanceof Error ? error.message : String(error)}`);\n    }\n}\ncli({\n    site: 'twitter',\n    name: 'likes',\n    access: 'read',\n    description: 'Fetch liked tweets of a Twitter user (defaults to the logged-in user when no username is given)',\n    domain: 'x.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'username', type: 'string', positional: true, help: 'Twitter screen name (with or without @). Defaults to the logged-in user when omitted.' },\n        { name: 'limit', type: 'int', default: 20, help: 'Maximum number of liked tweets to return (default 20). Ignored when --all is set.' },\n        { name: 'all', type: 'bool', default: false, help: 'Fetch all liked-tweet pages until exhausted. Prefer --output-file for large archives.' },\n        { name: 'resume-file', type: 'string', help: 'Resume file for long-running all-pages likes syncs.' },\n        { name: 'output-file', type: 'string', help: 'Write all-page results to JSONL. Requires --all and --resume-file.' },\n        { name: 'max-pages', type: 'int', help: `Optional pagination safety cap (default ${DEFAULT_MAX_PAGINATION_PAGES}; raised automatically with --all).` },\n        { name: 'top-by-engagement', type: 'int', default: 0, help: 'When set to N>0, re-rank the liked tweets by weighted engagement (likes×1 + retweets×3 + replies×2 + bookmarks×5 + log10(views+1)×0.5) and return the top N. Default 0 keeps the API\\'s native (recency) ordering. Incompatible with --output-file.' },","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/likes.js#L164-L200","documentation":"writeResumeFile persists resume state atomically via a temporary file that is later renamed over the target. If any filesystem operation (write, rename, mkdir) fails, the temp file is removed and the original error message is wrapped in a CommandExecutionError with this prefix. It signals the run's progress could not be saved to disk and the underlying OS error is embedded in the message.","triggerScenarios":"Calling --resume-file whose parent directory does not exist or is not writable; disk full; the temp file cannot be created/renamed due to permissions (read-only volume, EACCES, ENOSPC, EROFS); the path points at a directory.","commonSituations":"Typo in the resume file path's directory; running in a container with a read-only filesystem; disk quota exceeded on long full-archive scrapes; SMB/NFS mount dropped mid-run.","solutions":["Read the embedded OS error after the colon and fix it — e.g. create the parent directory (mkdir -p) the resume file path expects.","Check free disk space (df -h) and quotas; clear space if ENOSPC.","Verify the volume is writable (permissions, not mounted read-only) and the user running the CLI can write there.","Point --resume-file at a local writable path instead of a network mount, then move it after the run."],"exampleFix":"// before\nopencli twitter likes @jack --all --resume-file /nonexistent/dir/likes.json --output-file likes.ndjson\n// after\nmkdir -p ./resume && opencli twitter likes @jack --all --resume-file ./resume/likes.json --output-file likes.ndjson","handlingStrategy":"try-catch","validationCode":"const dir = path.dirname(resumePath);\nfs.mkdirSync(dir, { recursive: true });\nfs.accessSync(dir, fs.constants.W_OK);","typeGuard":null,"tryCatchPattern":"try {\n  await runLikes({ resumeFile });\n} catch (err) {\n  if (/Could not persist Twitter likes resume state/.test(err.message)) {\n    const cause = err.message.split(': ')[1];\n    console.error('Resume persist failed:', cause); // e.g. ENOSPC, EACCES\n    // fix disk/permissions, then resume from the last valid file\n  }\n}","preventionTips":["Pre-create the resume file's parent directory and confirm writability before long runs.","Monitor free disk space for full-archive jobs; resume files grow with the archive.","Use local disk for resume files, not read-only or flaky network mounts."],"tags":["filesystem","io","resume-file","persistence"],"backgroundTag":"file-write-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}