jackwener/OpenCLI · error · CommandExecutionError

Xiaoyuzhou playback progress returned unrequested eid ${eid}

Error message

Xiaoyuzhou playback progress returned unrequested eid ${eid}

What it means

parseProgressRows builds a Map of the eids it explicitly requested from the history page and rejects any progress row whose eid was not requested. This guards against the server returning unrelated or wrong-scope progress records, which would silently corrupt the history/progress join.

Source

Thrown at clis/xiaoyuzhou/history.js:119

        pubDate: optionalIsoTime(episode.pubDate, `pubDate in row ${rowNumber}`, { required: true }),
        finished: episode.isFinished,
    };
}

function parseProgressRows(response, episodes) {
    if (!Array.isArray(response?.data)) {
        throw new CommandExecutionError('Xiaoyuzhou playback progress returned an unexpected response shape');
    }
    const requested = new Map(episodes.map((episode) => [episode.eid, episode]));
    const progressById = new Map();
    for (const [index, row] of response.data.entries()) {
        if (!isRecord(row)) {
            throw new CommandExecutionError(`Xiaoyuzhou playback progress row ${index + 1} is malformed`);
        }
        const eid = requiredId(row.eid, `progress eid in row ${index + 1}`);
        const episode = requested.get(eid);
        if (!episode) {
            throw new CommandExecutionError(`Xiaoyuzhou playback progress returned unrequested eid ${eid}`);
        }
        if (progressById.has(eid)) {
            throw new CommandExecutionError(`Xiaoyuzhou playback progress returned duplicate eid ${eid}`);
        }
        const pid = requiredId(row.pid, `progress pid in row ${index + 1}`);
        if (pid !== episode.pid) {
            throw new CommandExecutionError(`Xiaoyuzhou playback progress pid did not match history eid ${eid}`);
        }
        const progressSec = optionalSeconds(row.progress, `progress in row ${index + 1}`);
        if (progressSec !== null && episode.durationSec !== null && progressSec > episode.durationSec) {
            throw new CommandExecutionError(`Xiaoyuzhou playback progress exceeded duration for eid ${eid}`);
        }
        progressById.set(eid, {
            progressSec,
            playedAt: optionalIsoTime(row.playedAt, `playedAt in row ${index + 1}`),
        });
    }
    for (const episode of episodes) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the eids sent in the request body match the returned rows — capture both sides of the call.
  2. Retry; a server-side filter regression may be transient or already fixed.
  3. Update the CLI/library in case id normalization (e.g. casing) changed and caused the mismatch.
  4. Check for server-side API changes where the progress endpoint stopped honoring the eids filter, and report it.
  5. As a workaround, use a lower --limit so fewer eids are in flight, reducing the chance of a mismatched row.

Example fix

// before (server ignores filter, returns everything)
{ "data": [ { "eid": "ffff...", "pid": "..." } ] }  // ffff... was not requested
// after
{ "data": [ { "eid": "aabb...", "pid": "...", "progress": 120 } ] }  // only requested eids
Defensive patterns

Strategy: validation

Validate before calling

function requestedOnly(progressRows, eids) { const set = new Set(eids.map(e => String(e).toLowerCase())); return progressRows.every(r => set.has(String(r?.eid ?? '').toLowerCase())); }

Type guard

function eidIsRequested(row, requestedEids) { return typeof row?.eid === 'string' && requestedEids.map(e => e.toLowerCase()).includes(row.eid.toLowerCase()); }

Try / catch

try {
  const rows = await runHistory();
} catch (e) {
  if (/returned unrequested eid/.test(e.message)) {
    // likely server ignoring the eids filter — retry, then report the API regression
  } else throw e;
}

Prevention

When it happens

Trigger: During `xiaoyuzhou history`, the progress endpoint returns a row whose eid is absent from the eids posted in the request body — e.g. the server ignores the eids filter, returns all account progress, or case-mismatched 24-hex ids fail the exact Map lookup.

Common situations: API regression where the eids filter is ignored; eid case differences (uppercase vs lowercase hex) after requiredId lowercased history ids; shared-account/sync quirks; mock fixtures returning canned full-list responses.

Related errors


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