{"record":{"id":"a8e4501118f9710d","repo":"jackwener/OpenCLI","slug":"bilibili-label-api-returned-a-malformed-payload-a8e450","errorCode":null,"errorMessage":"Bilibili ${label} API returned a malformed payload","messagePattern":"Bilibili (.+?) API returned a malformed payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/summary.js","lineNumber":60,"sourceCode":"            if (!match) {\n                throw new ArgumentError('Bilibili summary URL must contain a BV video id');\n            }\n            return match[1];\n        }\n        if (!B23_HOST_RE.test(parsed.hostname)) {\n            throw new ArgumentError('Bilibili summary URL must be a bilibili.com or b23.tv URL');\n        }\n    }\n    try {\n        return await resolveBvid(input);\n    } catch (error) {\n        throw new ArgumentError(`Cannot resolve Bilibili BV ID from input: ${input}`, error instanceof Error ? error.message : String(error));\n    }\n}\n\nfunction requireOkPayload(payload, label) {\n    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n        throw new CommandExecutionError(`Bilibili ${label} API returned a malformed payload`);\n    }\n    if (payload.code !== 0) {\n        const message = payload.message ?? 'unknown error';\n        if (payload.code === -101 || payload.code === -403 || /登录|权限|forbidden|permission|login/i.test(String(message))) {\n            throw new AuthRequiredError('bilibili.com', `Bilibili ${label} API requires login or permission: ${message} (${payload.code})`);\n        }\n        throw new CommandExecutionError(`Bilibili ${label} API failed: ${message} (${payload.code})`);\n    }\n    return payload.data;\n}\n\nfunction readModelResult(data, bvid) {\n    if (!data || typeof data !== 'object' || Array.isArray(data)) {\n        throw new CommandExecutionError('Bilibili conclusion API returned malformed data');\n    }\n    if (data.code !== 0) {\n        throw new EmptyResultError('bilibili summary', `Bilibili has not generated an AI summary for ${bvid}.`);\n    }","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/summary.js#L42-L78","documentation":"requireOkPayload() validates the raw JSON returned by a Bilibili API endpoint (used by viewData and conclusionData). If the body is not a non-array object — null, a string, an array, or unparseable output — it throws this CommandExecutionError because the response shape cannot even carry a code/message envelope. This signals an unexpected/changed API response rather than a logical API error.","triggerScenarios":"The Bilibili endpoint returns an empty body, an HTML error/anti-bot page parsed as garbage, a JSON array, or null because an HTTP layer already swallowed a non-JSON response; payload.code is absent and the object check at summary.js:59-61 fires first.","commonSituations":"Bilibili risk-control (风控) returning an HTML challenge instead of JSON; CDN/proxy intercepting the request; API contract change after a Bilibili update; a corporate proxy returning its own error page.","solutions":["Retry later or from a different network — the response is likely an anti-bot page or transient gateway error.","Send cookies/credentials expected by the web-interface endpoint if requests are being challenged.","Check whether the API response shape changed and update the CLI/parsing code.","Log the raw response body to confirm what was actually returned."],"exampleFix":"// before\nconst payload = await res.json(); // HTML body throws inside json() or yields junk\n// after\nconst text = await res.text();\nlet payload;\ntry { payload = JSON.parse(text); } catch { payload = null; }\nif (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n  throw new Error(`Unexpected response: ${text.slice(0, 200)}`);\n}","handlingStrategy":"try-catch","validationCode":"const text = await res.text();\nif (!text.trim().startsWith('{')) throw new Error(`Non-JSON response (likely anti-bot page): ${text.slice(0, 120)}`);","typeGuard":"function isApiEnvelope(x) {\n  return x !== null && typeof x === 'object' && !Array.isArray(x) && typeof x.code === 'number';\n}","tryCatchPattern":"try {\n  const rows = await summaryCommand(bvid);\n} catch (e) {\n  if (/malformed payload/.test(e.message)) {\n    // anti-bot page or API contract change: back off and retry, or inspect raw body\n    await sleep(2000);\n    return retrySummary(bvid);\n  }\n  throw e;\n}","preventionTips":["Send a browser-like User-Agent and valid cookies to avoid risk-control HTML pages.","Rate-limit batch requests to Bilibili endpoints.","Log raw response bodies on failure to diagnose intercepted responses.","Keep the CLI updated for API contract changes."],"tags":["api-response","malformed-json","anti-bot"],"backgroundTag":"malformed-api-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}