jackwener/OpenCLI · error · CommandExecutionError
Xiaoyuzhou history returned an unexpected response shape
Error message
Xiaoyuzhou history returned an unexpected response shape
What it means
parseHistoryPage first checks that the response object has both `data` and `raw` as records and that raw.data is identical to data — i.e. the envelope the auth/transport layer produced is intact. If the response is null, not an object, or the envelope is inconsistent, the history command cannot be trusted and throws CommandExecutionError.
Source
Thrown at clis/xiaoyuzhou/history.js:60
throw new CommandExecutionError(`Xiaoyuzhou history returned an invalid ${label}; expected seconds`);
}
return value;
}
function optionalIsoTime(value, label, { required = false } = {}) {
if (value === null) {
if (required) throw new CommandExecutionError(`Xiaoyuzhou history returned a missing ${label}`);
return null;
}
if (typeof value !== 'string' || !value.includes('T') || !Number.isFinite(Date.parse(value))) {
throw new CommandExecutionError(`Xiaoyuzhou history returned an invalid ${label}`);
}
return new Date(value).toISOString();
}
function parseHistoryPage(response) {
if (!isRecord(response) || !isRecord(response.raw) || response.raw.data !== response.data) {
throw new CommandExecutionError('Xiaoyuzhou history returned an unexpected response shape');
}
const payload = response?.data;
let entries;
let next;
if (Array.isArray(payload)) {
entries = payload;
next = response.raw?.loadMoreKey;
}
else if (isRecord(payload) && Array.isArray(payload.data)
&& !Object.prototype.hasOwnProperty.call(response.raw, 'loadMoreKey')) {
entries = payload.data;
next = payload.loadMoreKey;
}
else {
throw new CommandExecutionError('Xiaoyuzhou history returned an unexpected response shape');
}
if (next == null || next === '') return { entries, next: null };
if (typeof next !== 'string' || !next.trim()) {View on GitHub (pinned to 49907e53dc)
Solutions
- Re-authenticate: refresh or reload Xiaoyuzhou credentials (loadXiaoyuzhouCredentials) and retry.
- Check whether the API/domain is reachable and not being intercepted (VPN, proxy, captive portal) and retry from a plain network.
- Inspect the actual HTTP body returned by /v1/episode-played/list-history to see what shape came back.
- Update the CLI/library in case the transport envelope contract (raw.data === data) changed.
- If using mocks or an old version, align the mock/upgrade so requestXiaoyuzhouJson returns { data, raw, credentials }.
Example fix
// before (stub missing raw envelope)
return { data: json, credentials };
// after
return { data: json, raw: { data: json, ...rest }, credentials }; Defensive patterns
Strategy: try-catch
Validate before calling
function hasHistoryEnvelope(res) { return res !== null && typeof res === 'object' && !Array.isArray(res) && res.raw !== null && typeof res.raw === 'object' && res.raw.data === res.data; } Type guard
function isHistoryEnvelope(v) { return typeof v === 'object' && v !== null && 'data' in v && 'raw' in v && typeof v.raw === 'object' && v.raw !== null; } Try / catch
try {
const rows = await runHistory();
} catch (e) {
if (e.message === 'Xiaoyuzhou history returned an unexpected response shape') {
// refresh credentials / check network proxy, then retry once
} else throw e;
} Prevention
- Keep Xiaoyuzhou credentials fresh; re-login before long history fetches
- Disable or audit proxies/VPN/captive portals that can inject non-API bodies
- Keep requestXiaoyuzhouJson mocks in sync with the { data, raw, credentials } envelope
When it happens
Trigger: Calling the /v1/episode-played/list-history endpoint and getting a null/non-object response, or a response where response.raw.data !== response.data (transport wrapper inconsistent), typically from an auth error body, an HTML error page, or a proxy response that bypasses the wrapper.
Common situations: Expired credentials cause the API to return a login-redirect HTML body; a corporate proxy injects its own JSON error; using a stubbed requestXiaoyuzhouJson in tests that doesn't mirror raw/data; API version change replaces the JSON body entirely.
Related errors
- Xiaoyuzhou playback progress returned an unexpected response
- Bilibili ${label} API returned a malformed payload
- Bilibili ${label} API failed: ${message} (${payload.code})
- Boss recommend response did not include zpData.friendList
- Boss geek chat list response did not include zpData.friendLi
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3d74f00e97051d20.
Report an issue: GitHub.