{"record":{"id":"7120eec2c763bcdb","repo":"jackwener/OpenCLI","slug":"bilibili-creator-comparison-api-returned-malformed","errorCode":null,"errorMessage":"Bilibili creator comparison API returned malformed list data","messagePattern":"Bilibili creator comparison API returned malformed list data","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/creator-stats.js","lineNumber":60,"sourceCode":"function 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`,\n            { timeoutMs: FETCH_TIMEOUT_SECONDS * 1000 },\n        );\n        return requirePayload(payload);\n    }\n    catch (error) {\n        if (\n            error instanceof AuthRequiredError\n            || error instanceof EmptyResultError\n            || error instanceof CommandExecutionError\n            || error instanceof TimeoutError","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/creator-stats.js#L42-L78","documentation":"After the envelope's `code` passes (code === 0), requirePayload additionally requires payload.data to be a record containing an array `list`. If code is 0 but data/list is missing or of the wrong type, the response is considered contract-violating and this CommandExecutionError is thrown. This guards against success-shaped responses whose payload structure changed.","triggerScenarios":"Endpoint returns {code: 0, data: null}, {code: 0, data: {}}, or {code: 0, data: {list: {...}}} — e.g. Bilibili renamed `list`, moved it, or returns no data for accounts with zero analyzable manuscripts.","commonSituations":"Bilibili silently changing the undocumented response schema; brand-new creator accounts with no rows returning an empty/non-list data; probe fixtures drifting from production behavior.","solutions":["Log a sample of the raw payload (when code === 0) to see the new shape and update requirePayload's whitelist (payload.data.list) accordingly","Check whether the account has any manuscripts/analytics; try with an account that has published videos","Pin/retest against the sanitized creator-center probe fixtures to detect a schema drift","If Bilibili migrated the endpoint, find the new field name or endpoint and update the CLI"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function hasListShape(payload) {\n  return payload?.code === 0 && payload.data && !Array.isArray(payload.data) && Array.isArray(payload.data.list);\n}\n// call the endpoint once with a probe account and assert hasListShape before production use","typeGuard":"function hasValidListData(payload) {\n  return Boolean(payload?.data) && typeof payload.data === 'object' && !Array.isArray(payload.data) && Array.isArray(payload.data.list);\n}","tryCatchPattern":"try {\n  const rows = await runCommand();\n} catch (e) {\n  if (/malformed list data/.test(e.message)) {\n    // capture raw payload for diagnosis; check account has manuscripts / schema drift\n  } else throw e;\n}","preventionTips":["Test with an account that has published manuscripts and generated analytics","Keep probe fixtures refreshed against the live undocumented endpoint","Alert on schema drift: log raw payloads when code === 0 but data.list is absent","Track Bilibili creator-center API changes in a changelog"],"tags":["bilibili","schema-validation","api-contract","response-validation"],"backgroundTag":"api-response-schema-changed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}