jackwener/OpenCLI · error · ArgumentError

Resume file username mismatch: expected @${expected.username

Error message

Resume file username mismatch: expected @${expected.username}, found @${parsed.username || 'unknown'}

What it means

readResumeFile compares the resume file's `username` (case-insensitively) against the expected username for the current run and throws this ArgumentError on mismatch. This stops you from resuming another account's likes run with the wrong cursor context, which would corrupt results.

Source

Thrown at clis/twitter/likes.js:143

        parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
    }
    catch (error) {
        throw new CommandExecutionError(`Could not parse Twitter likes resume file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
    }
    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 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,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Resume with the same username the file was created for, or delete the file and start a fresh run for the new user
  2. Keep one resume file per (source, username) pair and name them accordingly
  3. Regenerate the resume file if the username field is missing or corrupted
  4. Verify the --username/expected argument you pass matches the original run

Example fix

// before
twitter likes --username userB --resume likes-userA.json
// after
twitter likes --username userA --resume likes-userA.json
// or fresh: twitter likes --username userB (new resume file)
Defensive patterns

Strategy: validation

Validate before calling

const parsed = JSON.parse(fs.readFileSync(resumePath, 'utf8'));
if (String(parsed.username || '').toLowerCase() !== targetUsername.toLowerCase())
  throw new Error(`resume file is for @${parsed.username}, not @${targetUsername}`);

Try / catch

try {
  await runLikes({ resume: resumePath, username: user });
} catch (e) {
  if (/username mismatch/.test(e.message)) {
    resumePath = `likes-${user}.json`; // switch to the correct per-user file or start fresh
  } else throw e;
}

Prevention

When it happens

Trigger: Running `twitter likes --resume <file>` while targeting user @B when the file records @A (parsed.username differs from expected.username, case-insensitive), or the file's username field is missing/blank so it resolves to 'unknown'.

Common situations: Switching target accounts between runs while reusing the same resume file; resuming a file saved from a different profile; a resume file whose username field was lost or stripped during manual editing.

Related errors


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