jackwener/OpenCLI · error · CommandExecutionError

Twitter bookmarks resume file ${filePath} count does not mat

Error message

Twitter bookmarks resume file ${filePath} count does not match its in-memory tweets

What it means

For in-memory resume files, the `count` field must exactly equal `tweets.length`. A mismatch means the state file is internally inconsistent, so readResumeFile throws this CommandExecutionError rather than resume with unreliable data.

Source

Thrown at clis/twitter/bookmarks.js:132

    }
    const count = parsed?.count;
    const cursor = parsed?.cursor == null ? null : String(parsed.cursor);
    const outputFile = parsed?.outputFile ? path.resolve(String(parsed.outputFile)) : null;
    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)
        || !Number.isInteger(count) || count < 0
        || (parsed.cursor != null && typeof parsed.cursor !== 'string')
        || (cursor !== null && !cursor.trim())) {
        throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} has an invalid shape`);
    }
    if (expected) {
        if (parsed.source !== expected.source)
            throw new ArgumentError(`Resume file source mismatch: expected ${expected.source}, found ${parsed.source || 'unknown'}`);
        if (outputFile !== expected.outputFile)
            throw new ArgumentError(`Resume file output mismatch: expected ${expected.outputFile || 'in-memory mode'}, found ${outputFile || 'in-memory mode'}`);
        if (!expected.outputFile && !Array.isArray(parsed.tweets))
            throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} is missing in-memory tweets`);
        if (!expected.outputFile && parsed.tweets.length !== count)
            throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} count does not match its in-memory tweets`);
        if (parsed.complete)
            throw new CommandExecutionError(`Twitter bookmarks resume file ${filePath} is already marked complete`);
    }
    return {
        cursor,
        count,
        tweets: Array.isArray(parsed.tweets) ? parsed.tweets : [],
        complete: Boolean(parsed.complete),
        source: parsed.source || null,
        outputFile,
        updatedAt: parsed.updatedAt || null,
    };
}

// 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)

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Fix `count` to match the actual length of `tweets` (only if you trust the file).
  2. Delete the resume file and restart the --all sync.
  3. Avoid editing resume files by hand; use --output-file mode where the JSONL archive is the source of truth.

Example fix

// before: {"count": 10, "tweets": [ /* 8 items */ ]}
// after: set count to actual length or regenerate
{"count": 8, "tweets": [ /* 8 items */ ], ...}
Defensive patterns

Strategy: validation

Validate before calling

const parsed = JSON.parse(fs.readFileSync(resumeFile, 'utf8'));
if (!parsed.outputFile && Array.isArray(parsed.tweets) && parsed.count !== parsed.tweets.length) {
  parsed.count = parsed.tweets.length; // or discard the file
  fs.writeFileSync(resumeFile, JSON.stringify(parsed, null, 2));
}

Type guard

function countMatchesTweets(v) {
  return v.outputFile || (Array.isArray(v.tweets) && v.count === v.tweets.length);
}

Try / catch

try {
  await run(args);
} catch (e) {
  if (String(e.message).includes('count does not match its in-memory tweets')) {
    fs.rmSync(resumeFile, { force: true });
    await run(args);
  } else throw e;
}

Prevention

When it happens

Trigger: Resuming a file where `count` was hand-edited, tweets were added/removed without updating `count`, or the file mixes fields from different runs (e.g. overwritten partially).

Common situations: Manual deduplication of the tweets array; truncated copy of the resume file; concurrent writes to the same resume file from two processes.

Related errors


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