jackwener/OpenCLI · error · CommandExecutionError

Twitter likes resume file ${filePath} count does not match i

Error message

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

What it means

readResumeFile validates a Twitter likes resume file against the current in-memory execution state. When the command runs in in-memory mode (--no output file), the resume file must contain a 'tweets' array whose length equals the tweet count recorded in the saved state. If the array length differs from the recorded count, the resume state is internally inconsistent, so the CLI refuses to trust it and throws CommandExecutionError.

Source

Thrown at clis/twitter/likes.js:149

    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 likes 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 (String(parsed.username || '').toLowerCase() !== String(expected.username).toLowerCase())
            throw new ArgumentError(`Resume file username mismatch: expected @${expected.username}, found @${parsed.username || '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 likes resume file ${filePath} is missing in-memory tweets`);
        if (!expected.outputFile && parsed.tweets.length !== count)
            throw new CommandExecutionError(`Twitter likes resume file ${filePath} count does not match its in-memory tweets`);
        if (parsed.complete)
            throw new CommandExecutionError(`Twitter likes resume file ${filePath} is already marked complete`);
    }
    return {
        cursor,
        count,
        tweets: Array.isArray(parsed.tweets) ? parsed.tweets : [],
        username: parsed.username || null,
        complete: Boolean(parsed.complete),
        source: parsed.source || null,
        outputFile,
        updatedAt: parsed.updatedAt || null,
    };
}

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

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Regenerate the resume file by re-running `opencli twitter likes <user> --all --output-file <path> --resume-file <path>` from scratch instead of resuming.
  2. Edit the resume file's 'count' field to equal the actual length of the 'tweets' array if you intentionally trimmed the tweets.
  3. Restore the resume file from a backup taken before it was modified.
  4. Verify in-memory mode is correct: if you meant to stream to disk, add --output-file so the tweets-array check is skipped.

Example fix

// before (inconsistent resume JSON)
{ "count": 150, "tweets": [ /* only 120 tweets */ ] }
// after
{ "count": 120, "tweets": [ /* the 120 tweets */ ] }
Defensive patterns

Strategy: validation

Validate before calling

const state = JSON.parse(fs.readFileSync(resumePath, 'utf8'));
if (!state.outputFile && Array.isArray(state.tweets) && state.tweets.length !== state.count) {
  throw new Error(`Resume file inconsistent: tweets.length=${state.tweets.length} but count=${state.count}`);
}

Type guard

function hasConsistentTweets(state) {
  return typeof state.outputFile === 'string' && state.outputFile
    || (Array.isArray(state.tweets) && state.tweets.length === state.count);
}

Prevention

When it happens

Trigger: Running `twitter likes --resume-file <path> --all` without --output-file, where the JSON in the resume file has a valid 'tweets' array but its parsed.tweets.length differs from the saved count field (e.g. the file was hand-edited, truncated, or written by a different version of the tool).

Common situations: Users manually trimming the tweets array in the resume JSON to shrink it; copying a resume file from another run whose count was recorded differently; a crash or partial write left the file with fewer tweets than the saved count.

Related errors


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