{"record":{"id":"c20a84d9495ae5c4","repo":"jackwener/OpenCLI","slug":"bilibili-creator-comparison-api-returned-a-malform","errorCode":null,"errorMessage":"Bilibili creator comparison API returned a malformed envelope","messagePattern":"Bilibili creator comparison API returned a malformed envelope","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/creator-stats.js","lineNumber":50,"sourceCode":"    { metric: 'thumbnailClickPct', key: 'tm_rate', unit: 'percent', divisor: 100 },\n    { metric: 'threeSecondExitPct', key: 'crash_rate', unit: 'percent', divisor: 100 },\n    { metric: 'interactionPct', key: 'interact_rate', unit: 'percent', divisor: 100 },\n    { metric: 'playToFollowerPct', key: 'play_trans_fan_rate', unit: 'percent', divisor: 100 },\n];\n\nfunction isRecord(value) {\n    return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isAuthLike(code, message) {\n    return code === -101\n        || code === -111\n        || /登录|账号未登录|login required|not logged in/i.test(String(message ?? ''));\n}\n\nfunction requirePayload(payload) {\n    if (!isRecord(payload) || !Number.isSafeInteger(payload.code)) {\n        throw new CommandExecutionError('Bilibili creator comparison API returned a malformed envelope');\n    }\n    const message = String(payload.message ?? payload.msg ?? 'unknown error');\n    if (payload.code !== 0) {\n        if (isAuthLike(payload.code, message)) {\n            throw new AuthRequiredError('member.bilibili.com', `Bilibili creator-center login is required: ${message}`);\n        }\n        throw new CommandExecutionError(`Bilibili creator comparison API failed: ${message} (${payload.code})`);\n    }\n    if (!isRecord(payload.data) || !Array.isArray(payload.data.list)) {\n        throw new CommandExecutionError('Bilibili creator comparison API returned malformed list data');\n    }\n    return payload.data.list;\n}\n\nasync function fetchComparison(page) {\n    try {\n        const payload = await page.fetchJson(\n            `${MEMBER_ORIGIN}/x/web/data/archive_diagnose/compare?size=100`,","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/creator-stats.js#L32-L68","documentation":"requirePayload validates the JSON body returned by Bilibili's undocumented archive_diagnose/compare endpoint before any field is read. A 'malformed envelope' means the parsed body was not an object, or had no safe-integer `code` field, so the standard Bilibili response contract (code/message/data) could not be trusted at all. The library throws this rather than guessing at an unparseable shape, because the endpoint is internal-unstable and PAGE_FETCH-based.","triggerScenarios":"page.fetchJson on https://member.bilibili.com/x/web/data/archive_diagnose/compare?size=100 returns JSON that is an array, a string, a number, null, or an object whose `code` is missing or not a safe integer (e.g. an HTML login page parsed as something else, a WAF/interstitial JSON, or a contract change by Bilibili).","commonSituations":"Expired or missing cookie session causing member.bilibili.com to return a non-standard body; Bilibili serving an anti-bot/verification interstitial; a Bilibili-side schema change to the undocumented endpoint; a proxy or captive portal intercepting the request.","solutions":["Log in to the Bilibili creator center (member.bilibili.com) in the browser session the CLI reuses so a valid session envelope is returned","Re-run after completing any captcha/verification challenge in the browser, then retry the command","Check whether Bilibili changed the endpoint response shape and update the whitelist/parse logic in requirePayload","Inspect the raw response (log payload) to confirm whether it is HTML, an interstitial, or a new JSON shape"],"exampleFix":"// before: blindly calling the command with a stale session\n$ opencli bilibili creator-stats BV1xx411c7mD\nCommandExecutionError: Bilibili creator comparison API returned a malformed envelope\n\n// after: refresh the creator-center login first\n$ # open member.bilibili.com in the browser, log in, then:\n$ opencli bilibili creator-stats BV1xx411c7mD","handlingStrategy":"type-guard","validationCode":"const res = await fetch('https://member.bilibili.com/x/web/data/archive_diagnose/compare?size=100', { headers: { cookie } });\nconst ct = res.headers.get('content-type') || '';\nif (!ct.includes('application/json')) throw new Error('non-JSON response — session likely invalid');","typeGuard":"function isBilibiliEnvelope(p) {\n  return Boolean(p) && typeof p === 'object' && !Array.isArray(p) && Number.isSafeInteger(p.code);\n}","tryCatchPattern":"try {\n  const rows = await runCommand();\n} catch (e) {\n  if (/malformed envelope/.test(e.message)) {\n    // prompt interactive login / check for anti-bot interstitial, then retry once\n  } else throw e;\n}","preventionTips":["Keep the browser session logged into member.bilibili.com before invoking the command","Complete any captcha/security challenge in the browser before running headless requests","Watch for Bilibili endpoint schema changes and pin fixtures to detect drift early"],"tags":["bilibili","api-contract","response-validation","network"],"backgroundTag":"api-response-envelope-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}