jackwener/OpenCLI · error · CommandExecutionError
Xiaoyuzhou playback progress pid did not match history eid $
Error message
Xiaoyuzhou playback progress pid did not match history eid ${eid} What it means
After resolving each progress row's eid to a requested episode, parseProgressRows verifies the row's pid (podcast id) equals the pid of the matching history episode. A mismatch means the progress row and the history entry describe different podcasts, so the join is inconsistent and the library refuses to produce misleading data.
Source
Thrown at clis/xiaoyuzhou/history.js:126
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) {
if (!progressById.has(episode.eid)) {
throw new CommandExecutionError(
`Xiaoyuzhou playback progress omitted requested eid ${episode.eid}; the history join is incomplete`,
);
}
}
return progressById;View on GitHub (pinned to 49907e53dc)
Solutions
- Log the offending eid, the progress pid, and the history episode pid and compare against a raw API response.
- Re-fetch history and progress in one session so both responses come from the same API version.
- Remove any local transformation of episode.pid before passing episodes into parseProgressRows.
- If the API genuinely changed field semantics, update the parsing code to the new contract.
Example fix
// before
episodes.push({ eid: entry.eid, pid: entry.podcast.id.toUpperCase(), ... });
return parseProgressRows(rows, episodes);
// after
episodes.push({ eid: entry.eid, pid: entry.podcast.id, ... }); // keep pid exactly as returned
return parseProgressRows(rows, episodes); Defensive patterns
Strategy: validation
Validate before calling
for (const r of progressRows) {
const ep = episodesById.get(r.eid);
if (ep && r.pid !== ep.pid) throw new Error(`pid mismatch for ${r.eid}: ${r.pid} != ${ep.pid}`);
} Try / catch
try {
const progress = progressById(episodes);
} catch (e) {
if (e instanceof CommandExecutionError && /pid did not match/.test(e.message)) {
console.error('History/progress join mismatch:', e.message);
} else throw e;
} Prevention
- Keep pid/eid values exactly as returned by the API; never transform them.
- Fetch history and progress in the same session so versions match.
- Compare pids in fixtures against live responses after API updates.
When it happens
Trigger: The progress API returns a pid for an eid that differs from the pid recorded in the history entry for that same eid — typically after an upstream API change, an eid/pid field swap, or stale/mixed responses from different endpoints.
Common situations: Server changes the meaning or casing of pid/eid fields; a proxy serves responses captured at different times; custom code mutates episode objects (e.g. remapping pids) before parsing; version skew between history and progress endpoints.
Related errors
- semanticscholar citations row is missing citingPaper
- Bilibili view API returned duplicate page entries for p=${pa
- Bilibili user search returned malformed result for ${input}
- Ctrip flight API returned a malformed batchSearch payload
- Ctrip flight API returned an itinerary without an id
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0ea5bfb0c4027c7c.
Report an issue: GitHub.