jackwener/OpenCLI · error · CliError

PARSE_ERROR

PARSE_ERROR

Error message

PARSE_ERROR

What it means

After calling POST /v1/episode/list, the CLI expects `response.data` to be an array of episodes. If the API returns an object, null, or a wrapped envelope instead, a CliError with code PARSE_ERROR is thrown so the user knows the response shape changed rather than silently emitting garbage rows.

Source

Thrown at clis/xiaoyuzhou/podcast-episodes.js:31

    args: [
        { name: 'id', positional: true, required: true, help: 'Podcast ID (from xiaoyuzhoufm.com URL)' },
        { name: 'limit', type: 'int', default: 20, help: 'Max episodes to show' },
    ],
    columns: ['eid', 'title', 'duration', 'plays', 'date'],
    func: async (args) => {
        const requestedLimit = Number(args.limit);
        if (!Number.isInteger(requestedLimit) || requestedLimit < 1) {
            throw new CliError('INVALID_ARGUMENT', 'limit must be a positive integer', 'Example: --limit 5');
        }
        const credentials = loadXiaoyuzhouCredentials();
        const response = await requestXiaoyuzhouJson('/v1/episode/list', {
            method: 'POST',
            body: { pid: args.id, order: 'desc', limit: requestedLimit },
            credentials,
        });
        const episodes = response.data ?? [];
        if (!Array.isArray(episodes)) {
            throw new CliError('PARSE_ERROR', 'Unexpected API response format', 'Expected an array of episodes');
        }
        return episodes.map((ep) => ({
            eid: ep.eid,
            title: ep.title,
            duration: formatDuration(ep.duration),
            plays: ep.playCount,
            date: formatDate(ep.pubDate),
        }));
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command; transient error envelopes can cause this
  2. Verify credentials are valid (`xq`-style auth failures can change the payload shape)
  3. Check for xiaoyuzhou API/CLI version mismatch and update the CLI
  4. Inspect the raw response (e.g. via verbose logging) to confirm the new schema
Defensive patterns

Strategy: type-guard

Validate before calling

const res = await requestXiaoyuzhouJson('/v1/episode/list', {method:'POST', body:{pid, order:'desc', limit}});
if (!Array.isArray(res?.data)) throw new Error('Unexpected episode list shape');

Type guard

const isEpisodeArray = (d) => Array.isArray(d) && d.every(e => e && typeof e.eid === 'string');

Try / catch

try { const eps = await fetchEpisodes(pid, limit); } catch (e) { if (String(e).includes('PARSE_ERROR')) { logRawResponseForDebugging(); } throw e; }

Prevention

When it happens

Trigger: The xiaoyuzhou API returns a non-array `data` field for /v1/episode/list — e.g. an error envelope `{error: ...}`, `{data: {items: []}}` shape change, or an HTML/JSON error page parsed into an object.

Common situations: API version drift after a xiaoyuzhou backend update, hitting a rate-limit or auth-failure payload that isn't the expected list, or a proxy/captive portal returning HTML that gets parsed as a JSON object.

Related errors


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