jackwener/OpenCLI · error · ArgumentError

Refusing to overwrite existing Twitter likes output file: ${

Error message

Refusing to overwrite existing Twitter likes output file: ${outputFile}

What it means

ArgumentError thrown when no resume state exists but the requested output JSONL file already exists on disk. The library refuses to overwrite existing archives to protect previously fetched data from being clobbered by a fresh run.

Source

Thrown at clis/twitter/likes.js:280

      const url = ${JSON.stringify(buildUserByScreenNameQueryUrl(userByScreenNameQueryId, username))};
      const resp = await fetch(url, { headers: ${headers}, credentials: 'include' });
      if (!resp.ok) return null;
      const d = await resp.json();
      return d.data?.user?.result?.rest_id || null;
    }`));
        if (!userId) {
            throw new CommandExecutionError(`Could not find user @${username}`);
        }
        const resumed = fetchAll ? readResumeFile(resumeFile, {
            source: 'likes',
            username,
            outputFile: useOutputFile ? outputFile : null,
        }) : null;
        if (useOutputFile && resumed && resumed.count > 0 && !fs.existsSync(outputFile)) {
            throw new CommandExecutionError(`Twitter likes output file is missing for resume state: ${outputFile}`);
        }
        if (useOutputFile && !resumed && fs.existsSync(outputFile)) {
            throw new ArgumentError(`Refusing to overwrite existing Twitter likes output file: ${outputFile}`);
        }
        const allTweets = useOutputFile ? [] : (resumed?.tweets ? [...resumed.tweets] : []);
        const jsonlState = useOutputFile ? loadJsonlArchiveState(outputFile) : null;
        const seen = useOutputFile
            ? jsonlState.seen
            : new Set(allTweets.map((tweet) => tweet?.id).filter(Boolean));
        if (useOutputFile && resumed && jsonlState.count !== resumed.count) {
            throw new CommandExecutionError(`Twitter likes output file has ${jsonlState.count} record(s), expected resume count ${resumed.count}`);
        }
        let outputCount = useOutputFile ? jsonlState.count : 0;
        let cursor = resumed?.cursor || null;
        let lastRawResponse = null;
        let pages = 0;
        let exhausted = false;
        // Runaway guard only; --limit/--all and cursor exhaustion control normal pagination.
        while (pages < maxPages && (fetchAll || allTweets.length < limit)) {
            pages += 1;
            const currentCount = useOutputFile ? outputCount : allTweets.length;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Add the --resume flag to continue appending to the existing archive.
  2. Choose a new --output file path for the fresh run.
  3. Delete or rename the existing output file if you truly want to start over.
  4. Back up the existing JSONL before deleting it.

Example fix

// before
$ cli twitter likes @user --output likes.jsonl  # likes.jsonl already exists
// after
$ cli twitter likes @user --output likes.jsonl --resume
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('node:fs');
if (fs.existsSync(outputFile) && !wantsResume) {
  outputFile = `likes-${Date.now()}.jsonl`; // pick a fresh name
}

Type guard

null

Try / catch

try {
  await cli.twitter.likes({ username, output: outputFile });
} catch (e) {
  if (/Refusing to overwrite/.test(e.message)) {
    await cli.twitter.likes({ username, output: outputFile, resume: true });
  } else throw e;
}

Prevention

When it happens

Trigger: useOutputFile is true, readResumeFile returned null (no resume file), and fs.existsSync(outputFile) is true when reaching clis/twitter/likes.js:280.

Common situations: Re-running the same command twice without --resume; a previous run crashed after writing rows but the resume file was removed; intentionally re-collecting while pointing at last week's archive.

Related errors


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