{"record":{"id":"d35d0288cfb5d377","repo":"jackwener/OpenCLI","slug":"bilibili-view-api-failed-payload-message-pa","errorCode":null,"errorMessage":"Bilibili view API failed: ${payload.message} (${payload.code})","messagePattern":"Bilibili view API failed: (.+?) \\((.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/video.js","lineNumber":69,"sourceCode":"    // Resolve BV ID from three advertised input forms:\n    //   1. Bare \"BV...\" id\n    //   2. Full bilibili.com/video/<BV>... URL (with or without query string / www / m.)\n    //   3. b23.tv short link (delegated to resolveBvid)\n    // resolveBvid() alone handles (1) and (3) but not (2), so we pre-extract\n    // from bilibili URLs before falling through.\n    const input = String(kwargs.bvid ?? '').trim();\n    const bilibiliUrlMatch = input.match(/bilibili\\.com\\/(?:video|bangumi\\/play)\\/(BV[A-Za-z0-9]+)/i);\n    const bvid = bilibiliUrlMatch ? bilibiliUrlMatch[1] : await resolveBvid(input);\n\n    // Navigate to video page first so subsequent api call shares a primed session.\n    await page.goto(`https://www.bilibili.com/video/${bvid}/`);\n\n    const payload = unwrapBrowserResult(await apiGet(page, '/x/web-interface/view', {\n      params: { bvid },\n    }));\n    requireObject(payload, 'Bilibili view API');\n    if (payload.code !== 0) {\n      throw new CommandExecutionError(`Bilibili view API failed: ${payload.message} (${payload.code})`);\n    }\n\n    const d = requireObject(payload.data, 'Bilibili view API data');\n    const stat = d.stat || {};\n    const owner = d.owner || {};\n\n    // 付费/会员标记：view API 的 rights 位 + 充电专属字段本来就在响应里，\n    // 透出给下游在下载/截屏前判断\"拿不到视频流\"。\n    //   rights.pay=1                  → 付费 OGV（大会员专享/单点付费番剧、影视；实测会员番剧单集 pay=1）\n    //   rights.ugc_pay=1 / arc_pay=1  → UGC 单点付费 / 付费合集\n    //   is_upower_exclusive=true      → 充电专属视频\n    // redirect_url 非空（指向 /bangumi/play/ep<id>）= OGV 内容，细分可再查 pgc season API。\n    const rights = requireObject(d.rights, 'Bilibili view API data.rights');\n    const rightsPay = readOptionalFlag(rights.pay, 'Bilibili rights.pay');\n    const rightsUgcPay = readOptionalFlag(rights.ugc_pay, 'Bilibili rights.ugc_pay');\n    const rightsArcPay = readOptionalFlag(rights.arc_pay, 'Bilibili rights.arc_pay');\n    const upowerExclusive = readOptionalFlag(d.is_upower_exclusive, 'Bilibili is_upower_exclusive');\n    const paymentType = rightsPay","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/video.js#L51-L87","documentation":"After fetching /x/web-interface/view, the video command checks payload.code; Bilibili APIs signal failure via a non-zero code plus a message. This CommandExecutionError surfaces the API's own message and code (e.g. -404 video not found, -403 forbidden, -352 risk control) instead of failing opaquely.","triggerScenarios":"Any non-zero code from the view API: invalid/nonexistent bvid, region-locked or deleted video, rate limiting (-412/-352), or requiring login for mature content.","commonSituations":"Typo in the BV ID; video deleted or made private; accessing from a blocked region/IP; hitting Bilibili rate limits after many rapid requests.","solutions":["Verify the BV ID / URL is correct and the video is still public","Retry with backoff if the code indicates rate limiting (-412, -352) or use a fresh browser session/IP","Log in / refresh the browser session if the video requires authentication","Check the code against Bilibili API error docs (e.g. -404 = not found) to choose the right remedy"],"exampleFix":"// before\nconst d = requireObject(payload.data, 'Bilibili view API data');\n// after\nif (payload.code !== 0) {\n  if (payload.code === -404) console.error('Video not found — check the BV ID');\n  else throw new CommandExecutionError(`Bilibili view API failed: ${payload.message} (${payload.code})`);\n  return;\n}\nconst d = requireObject(payload.data, 'Bilibili view API data');","handlingStrategy":"try-catch","validationCode":"// validate BV id format before calling\nif (!/^BV[0-9A-Za-z]{10}$/.test(bvid)) throw new Error(`invalid bvid: ${bvid}`);","typeGuard":"null","tryCatchPattern":"try { const info = await videoInfo(bvid); }\ncatch (e) {\n  if (e instanceof CommandExecutionError && e.message.startsWith('Bilibili view API failed')) {\n    const code = Number(e.message.match(/\\((-?\\d+)\\)$/)?.[1]);\n    if (code === -404) console.error('Video not found');\n    else if ([-412, -352].includes(code)) await sleep(5000); // retry on rate-limit\n    else throw e;\n  } else throw e;\n}","preventionTips":["Validate bvid format before API calls","Back off on rate-limit codes (-412, -352)","Keep sessions logged in for restricted content","Distinguish per-code handling instead of one generic retry"],"tags":["api-error","bilibili","rate-limit"],"backgroundTag":"upstream-api-error-code","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}