jackwener/OpenCLI · error · CommandExecutionError
Could not persist Twitter bookmarks resume state: ${error in
Error message
Could not persist Twitter bookmarks resume state: ${error instanceof Error ? error.message : String(error)} What it means
writeResumeFile persists state atomically: it writes `${filePath}.tmp-${pid}` then renames onto the resume file. If the write or rename fails, it removes the temp file and throws this CommandExecutionError wrapping the underlying message (ENOENT, EACCES, ENOSPC, EPERM, etc.).
Source
Thrown at clis/twitter/bookmarks.js:164
// Keep this in sync with twitter/likes; wording is command-specific, so the
// atomic tmp-write/rename cleanup sequence intentionally remains local.
function writeResumeFile(filePath, payload) {
if (!filePath)
return;
ensureParentDir(filePath);
const temporaryPath = `${filePath}.tmp-${process.pid}`;
try {
fs.writeFileSync(temporaryPath, JSON.stringify(payload, null, 2) + '\n');
fs.renameSync(temporaryPath, filePath);
}
catch (error) {
try {
fs.rmSync(temporaryPath, { force: true });
}
catch {
}
throw new CommandExecutionError(`Could not persist Twitter bookmarks resume state: ${error instanceof Error ? error.message : String(error)}`);
}
}
cli({
site: 'twitter',
name: 'bookmarks',
access: 'read',
description: 'Fetch your Twitter/X bookmarks (the logged-in user\'s saved tweets, newest first)',
domain: 'x.com',
strategy: Strategy.COOKIE,
browser: true,
args: [
{ name: 'limit', type: 'int', default: 20, help: 'Maximum number of bookmarks to return (default 20). Ignored when --all is set.' },
{ name: 'all', type: 'bool', default: false, help: 'Fetch all bookmark pages until exhausted. Prefer --output-file for large archives.' },
{ name: 'resume-file', type: 'string', help: 'Resume file for long-running all-pages bookmark syncs.' },
{ name: 'output-file', type: 'string', help: 'Write all-page results to JSONL. Requires --all and --resume-file.' },
{ name: 'max-pages', type: 'int', help: `Optional pagination safety cap (default ${DEFAULT_MAX_PAGINATION_PAGES}; raised automatically with --all).` },
{ name: 'top-by-engagement', type: 'int', default: 0, help: 'When set to N>0, re-rank the bookmarks 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 (saved-time) ordering. Incompatible with --output-file.' },
],View on GitHub (pinned to 49907e53dc)
Solutions
- Check disk space (`df -h`) and free space if ENOSPC.
- Verify the resume-file's parent directory exists and is writable by the current user (mkdir/chown/chmod).
- Point --resume-file at a writable path (e.g. $HOME or a writable volume).
- If a stale `.tmp-<pid>` file exists and is locked, remove it and retry; on Windows, close tools holding the file.
Example fix
// before: fails cli twitter bookmarks --all --resume-file /proc/run/b.json // EACCES/ENOENT -> Could not persist Twitter bookmarks resume state // after: mkdir -p ~/var/lib/twitter-sync cli twitter bookmarks --all --resume-file ~/var/lib/twitter-sync/bookmarks.json --output-file ~/var/lib/twitter-sync/archive.jsonl
Defensive patterns
Strategy: try-catch
Validate before calling
const dir = path.dirname(resumeFile);
fs.mkdirSync(dir, { recursive: true });
fs.accessSync(dir, fs.constants.W_OK);
// also check free space if the sync is large
const stat = fs.statfsSync(dir);
if (stat.bsize * stat.bavail < 10 * 1024 * 1024) throw new Error('low disk space'); Type guard
null
Try / catch
try {
await run(['twitter', 'bookmarks', '--all', '--resume-file', p, '--output-file', o]);
} catch (e) {
if (String(e.message).includes('Could not persist Twitter bookmarks resume state')) {
console.error('resume write failed:', e.message);
const writable = path.join(os.tmpdir(), 'bookmarks-resume.json');
await run(['twitter', 'bookmarks', '--all', '--resume-file', writable, '--output-file', o]);
} else throw e;
} Prevention
- Point --resume-file at a writable, non-volatile directory ($HOME, writable volume).
- Monitor disk space before long --all syncs.
- Avoid read-only mounts and root-owned paths for state files.
- Clean stale `.tmp-<pid>` files after crashes.
When it happens
Trigger: Resume-file directory does not exist and cannot be created (permissions); disk full (ENOSPC); read-only filesystem; the target path is a directory; another process/AV locks the file during rename on some platforms.
Common situations: --resume-file pointing under a root-owned or read-only directory; container volumes mounted read-only; quota exceeded on a long --all sync; resume path inside a deleted working directory.
Related errors
- Could not persist Twitter likes resume state: ${error instan
- Verify command returned no metric for baseline
- File not found: ${path}
- File must be a readable text file: ${path}
- File could not be read: ${path}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/fff4b72b3da0acf0.
Report an issue: GitHub.