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

  1. Re-authenticate: refresh or reload Xiaoyuzhou credentials (loadXiaoyuzhouCredentials) and retry.
  2. Check whether the API/domain is reachable and not being intercepted (VPN, proxy, captive portal) and retry from a plain network.
  3. Inspect the actual HTTP body returned by /v1/episode-played/list-history to see what shape came back.
  4. Update the CLI/library in case the transport envelope contract (raw.data === data) changed.
  5. 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

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


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