{"record":{"id":"864b0b10cd477b28","repo":"jackwener/OpenCLI","slug":"bilibili-label-api-failed-message-payloa-864b0b","errorCode":null,"errorMessage":"Bilibili ${label} API failed: ${message} (${payload.code})","messagePattern":"Bilibili (.+?) API failed: (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/utils.js","lineNumber":235,"sourceCode":" * `code` carries either an auth/permission failure (login expired, CSRF rejected,\n * forbidden) or an application-level error (rate limit, validation, etc.). These\n * two helpers route the envelope to the right typed error so every write adapter\n * surfaces login problems as `AuthRequiredError`, not a generic execution error.\n */\nexport function isAuthLikeBilibiliError(code, message) {\n    return code === -101 || code === -111 || code === -403 || /csrf|登录|账号|权限|forbidden|permission|login/i.test(String(message ?? ''));\n}\n\nexport function requireOkPayload(payload, label) {\n    if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'code')) {\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 (isAuthLikeBilibiliError(payload.code, 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\n/**\n * POST form-encoded params to a Bilibili API endpoint.\n * Runs inside the logged-in browser context and auto-attaches the bili_jct CSRF token,\n * which Bilibili requires on every authenticated write request.\n */\nexport async function apiPost(page, path, opts = {}) {\n    const params = opts.params ?? {};\n    const stringified = Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)]));\n    const paramsJs = JSON.stringify(stringified);\n    const urlJs = JSON.stringify(`https://api.bilibili.com${path}`);\n    return page.evaluate(`\n    async () => {\n      const csrf = (document.cookie.match(/bili_jct=([^;]+)/) || [])[1] || \"\";\n      const body = new URLSearchParams(${paramsJs});","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/utils.js#L217-L253","documentation":"The Bilibili API returned valid JSON with a non-zero `code` that was NOT auth-like, so the library surfaces the API's own message and code as a CommandExecutionError. This is the generic 'API said no' path — the server processed the request but rejected it for a business reason.","triggerScenarios":"payload.code !== 0 with codes like -400 (bad request), -404 (not found), 62002 (video invisible/hidden), -509 (risk control), 62012 (comments closed), etc., and the message doesn't match the auth regex.","commonSituations":"Malformed aid/bvid parameters; deleted or made-private videos; Bilibili risk-controlling datacenter IPs; passing wrong params to a specific endpoint (e.g., wrong search_type); region-locked content.","solutions":["Read the code/message in the error — Bilibili's codes are documented (e.g., -404 not found, 62002 hidden video) and indicate the exact problem.","Verify the aid/bvid/params you passed are correct and the video still exists and is public.","If you get risk-control codes (-509/-412), slow request rate, use cookies, or a residential IP.","Retry with backoff only for transient codes; do not retry permanent codes like -400/-404."],"exampleFix":"// before\ntry { await download(url); }\ncatch (e) { retry(url); } // retries even for -404\n// after\ntry { await download(url); }\ncatch (e) {\n  if (!/-40[04]|62002/.test(e.message)) retry(url);\n  else console.error('Permanent API rejection:', e.message);\n}","handlingStrategy":"try-catch","validationCode":"// preflight: check the video is public and exists\nconst v = await (await fetch(`https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`)).json();\nif (v.code === -404 || v.code === 62002) throw new Error(`Video unavailable: ${v.message}`);","typeGuard":null,"tryCatchPattern":"try { const data = requireOkPayload(payload, 'view'); } catch (e) { const m = /\\((-[0-9]+)\\)$/.exec(e.message); if (m && ['-400','-404','62002'].includes(m[1])) { /* permanent: don't retry */ } else if (m && ['-509','-412'].includes(m[1])) { await backoffAndRetry(); } else throw e; }","preventionTips":["Learn Bilibili's common codes: -400 bad request, -404 not found, 62002 hidden video, -509 risk control.","Validate aid/bvid and endpoint params before sending.","Rate-limit requests and use cookies/residential IPs to avoid risk-control codes.","Only retry transient codes; fail fast on permanent ones."],"tags":["api","bilibili","error-code","request"],"backgroundTag":"api-error-code","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}