jackwener/OpenCLI · error · CliError
PARSE_ERROR
PARSE_ERROR
Error message
Invalid ZSXQ API response
What it means
unwrapRespData validates the shape of a ZSXQ API JSON payload before extracting resp_data. If the payload is not a plain object (asRecord returns null), it throws CliError PARSE_ERROR 'Invalid ZSXQ API response'. The library throws this because it cannot safely read succeeded/code/resp_data from a non-object payload.
Source
Thrown at clis/zsxq/utils.js:136
}
export async function fetchFirstJson(page, paths) {
let lastFailure = null;
for (const path of paths) {
const result = await browserJsonRequest(page, path);
if (result.ok) {
return result;
}
lastFailure = result;
}
if (!lastFailure) {
throw new CliError('FETCH_ERROR', 'No candidate endpoint returned JSON', `Checked endpoints: ${paths.join(', ')}`);
}
throw new CliError('FETCH_ERROR', lastFailure.error || 'Failed to fetch ZSXQ API', `Checked endpoints: ${paths.join(', ')}`);
}
export function unwrapRespData(payload) {
const record = asRecord(payload);
if (!record) {
throw new CliError('PARSE_ERROR', 'Invalid ZSXQ API response');
}
if (record.succeeded === false) {
const code = typeof record.code === 'number' ? String(record.code) : 'API_ERROR';
const message = typeof record.info === 'string'
? record.info
: typeof record.error === 'string'
? record.error
: 'ZSXQ API returned an error';
throw new CliError(code, message);
}
return (record.resp_data ?? record.data ?? payload);
}
export function getTopicsFromResponse(payload) {
const data = unwrapRespData(payload);
if (Array.isArray(data))
return data;
return pickArray(data.topics, data.list, data.records, data.items, data.search_result);
}View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw payload before unwrapping to see the actual response shape
- Re-run with a fresh authenticated request — a stale/cached HTML-to-JSON artifact is common
- Update the library if ZSXQ changed its response envelope (succeeded/code/resp_data)
Example fix
// before
const data = unwrapRespData(payload);
// after
const record = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload : null;
if (!record) throw new Error('unexpected payload: ' + JSON.stringify(payload).slice(0, 200));
const data = unwrapRespData(record); Defensive patterns
Strategy: type-guard
Validate before calling
const isRecord = (p) => !!p && typeof p === 'object' && !Array.isArray(p);
if (!isRecord(payload)) throw new Error('Non-object ZSXQ payload: ' + JSON.stringify(payload).slice(0, 200)); Type guard
function isApiRecord(p) {
return typeof p === 'object' && p !== null && !Array.isArray(p);
} Try / catch
try {
const data = unwrapRespData(payload);
} catch (e) {
if (e.code === 'PARSE_ERROR') console.error('Unexpected ZSXQ payload shape', payload);
else throw e;
} Prevention
- Log raw payloads once when integrating a new endpoint to learn its envelope
- Check for proxies/WAFs that replace API JSON with their own JSON bodies
- Update parsing assumptions when the API envelope (succeeded/code/resp_data) changes
When it happens
Trigger: Calling data() (which routes through unwrapRespData) when the endpoint returned JSON that is not an object — e.g. an array, a string, or null payload from an unexpected response.
Common situations: API contract change returning a different JSON envelope; a proxy returning JSON like "ok" or [1,2]; a mocked/captured response reused incorrectly; CDN or WAF returning an error page that happens to parse as JSON.
Related errors
- ${label} returned JSON without result.status.@code
- 12306 ${endpoint} returned an unexpected payload shape
- ${label} returned an unexpected payload shape; expected an o
- archive snapshots returned malformed CDX payload: top-level
- archive snapshots returned malformed CDX payload: header row
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/07fdb8a429b3faaf.
Report an issue: GitHub.