jackwener/OpenCLI · error · CommandExecutionError

Could not persist Twitter likes resume state: ${error instan

Error message

Could not persist Twitter likes resume state: ${error instanceof Error ? error.message : String(error)}

What it means

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.

Source

Thrown at clis/twitter/likes.js:182

// Keep this in sync with twitter/bookmarks; 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 likes resume state: ${error instanceof Error ? error.message : String(error)}`);
    }
}
cli({
    site: 'twitter',
    name: 'likes',
    access: 'read',
    description: 'Fetch liked tweets of a Twitter user (defaults to the logged-in user when no username is given)',
    domain: 'x.com',
    strategy: Strategy.COOKIE,
    browser: true,
    args: [
        { name: 'username', type: 'string', positional: true, help: 'Twitter screen name (with or without @). Defaults to the logged-in user when omitted.' },
        { name: 'limit', type: 'int', default: 20, help: 'Maximum number of liked tweets to return (default 20). Ignored when --all is set.' },
        { name: 'all', type: 'bool', default: false, help: 'Fetch all liked-tweet pages until exhausted. Prefer --output-file for large archives.' },
        { name: 'resume-file', type: 'string', help: 'Resume file for long-running all-pages likes 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 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.' },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the embedded OS error after the colon and fix it — e.g. create the parent directory (mkdir -p) the resume file path expects.
  2. Check free disk space (df -h) and quotas; clear space if ENOSPC.
  3. Verify the volume is writable (permissions, not mounted read-only) and the user running the CLI can write there.
  4. Point --resume-file at a local writable path instead of a network mount, then move it after the run.

Example fix

// before
opencli twitter likes @jack --all --resume-file /nonexistent/dir/likes.json --output-file likes.ndjson
// after
mkdir -p ./resume && opencli twitter likes @jack --all --resume-file ./resume/likes.json --output-file likes.ndjson
Defensive patterns

Strategy: try-catch

Validate before calling

const dir = path.dirname(resumePath);
fs.mkdirSync(dir, { recursive: true });
fs.accessSync(dir, fs.constants.W_OK);

Try / catch

try {
  await runLikes({ resumeFile });
} catch (err) {
  if (/Could not persist Twitter likes resume state/.test(err.message)) {
    const cause = err.message.split(': ')[1];
    console.error('Resume persist failed:', cause); // e.g. ENOSPC, EACCES
    // fix disk/permissions, then resume from the last valid file
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/76aff50b230be529. Report an issue: GitHub.