{"record":{"id":"9c156d5adb56ff50","repo":"DIYgod/RSSHub","slug":"response-message","errorCode":null,"errorMessage":"response.message","messagePattern":"response\\.message","errorType":"exception","errorClass":null,"httpStatus":503,"severity":"error","filePath":"lib/routes/bilibili/ranking.ts","lineNumber":254,"sourceCode":"\n    const rid = ctx.req.param('rid') || 'all';\n    const embed = !ctx.req.param('embed');\n    const isNumericRid = /^\\d+$/.test(rid);\n\n    const { apiBase, apiParams, referer, ridChinese, link, ridType } = getAPI(isNumericRid, rid);\n    if (ridType.startsWith('pgc/')) {\n        throw new Error('This type of ranking is not supported yet');\n    }\n\n    const response = await ofetch(`${apiBase}?${apiParams}`, {\n        headers: {\n            Referer: referer,\n            origin: 'https://www.bilibili.com',\n        },\n    });\n\n    if (response.code !== 0) {\n        throw new Error(response.message);\n    }\n    const data = response.data || response.result;\n    const list = data.list || [];\n    return {\n        title: `bilibili 排行榜-${ridChinese}`,\n        link,\n        item: await Promise.all(\n            list.map(async (item) => {\n                const subtitles = isJsonFeed && !config.bilibili.excludeSubtitles && item.bvid ? await cache.getVideoSubtitleAttachment(item.bvid) : [];\n                return {\n                    title: item.title,\n                    description: utils.renderUGCDescription(embed, item.pic, item.desc || item.title, item.aid, undefined, item.bvid),\n                    pubDate: item.ctime && parseDate(item.ctime, 'X'),\n                    author: item.owner.name,\n                    link: !item.ctime || (item.ctime > utils.bvidTime && item.bvid) ? `https://www.bilibili.com/video/${item.bvid}` : `https://www.bilibili.com/video/av${item.aid}`,\n                    image: item.pic,\n                    attachments: item.bvid\n                        ? [","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/bilibili/ranking.ts#L236-L272","documentation":"Thrown by the ranking handler when the GET to `${apiBase}?${apiParams}` (e.g. https://api.bilibili.com/x/web-interface/ranking/v2) returns HTTP 200 with a non-zero business code. Unlike other bilibili routes it propagates `response.message` directly with no fallback, so if the upstream omits the field the thrown Error will have an empty/undefined message. A non-zero code typically means Bilibili rejected the request (risk control, web_location signature issue, or region restriction).","triggerScenarios":"GET /bilibili/ranking/:rid where the ranking/v2 endpoint answers code !== 0 — commonly -352/-799 (risk control / anti-crawler) when RSSHub is rate-limited or missing the w_rid/wts wbi signature, or -479 (恶意请求) on aggressive polling.","commonSituations":"Public RSSHub instance IP flagged by Bilibili's anti-crawler; missing/rotated wbi signing keys; the ranking endpoint now requires a w_rid/wts pair not appended here; transient upstream error.","solutions":["Retry after a short cooldown — many -352/-479 responses are transient rate-limit signals.","If you self-host, route RSSHub through a residential/cleaner IP or add the wbi signature (w_rid, wts) to apiParams as the comments at the top of ranking.ts already imply is required.","Reduce polling frequency and avoid concurrent requests to the same ranking endpoint.","If response.message is empty, patch the throw to include the code: `throw new Error(response.message || 'Error code ' + response.code)`."],"exampleFix":"// before\nif (response.code !== 0) {\n    throw new Error(response.message);\n}\n\n// after (guarantee a non-empty, actionable message)\nif (response.code !== 0) {\n    throw new Error(response.message || `Bilibili ranking API error: code ${response.code}`);\n}","handlingStrategy":"retry","validationCode":"// Soft pre-flight: probe the ranking endpoint and surface risk-control early.\nimport ofetch from '@/utils/ofetch';\nasync function rankingReachable(apiBase: string, apiParams: string) {\n  try {\n    const r = await ofetch<{ code: number }>(`${apiBase}?${apiParams}`, { headers: { Referer: 'https://www.bilibili.com/' } });\n    return r.code === 0;\n  } catch { return false; }\n}","typeGuard":"interface RankEnv<T> { code: number; message?: string; data?: T; result?: T }\nfunction isRankOk<T>(r: RankEnv<T>): r is RankEnv<T> & { code: 0 } { return r.code === 0; }","tryCatchPattern":"try {\n  if (response.code !== 0) throw new Error(response.message);\n} catch (e) {\n  const m = (e instanceof Error ? e.message : '') || '';\n  if (m.includes('-352') || m.includes('-479') || m.includes('-799')) {\n    // transient anti-crawler — retry with backoff\n    await backoffRetry(() => ofetch(`${apiBase}?${apiParams}`, opts));\n  }\n  throw e;\n}","preventionTips":["If you self-host, append the wbi signature (w_rid, wts) to apiParams so bilibili does not return -352/-479 for unsigned requests.","Cache the ranking result for several minutes to avoid repeated upstream calls.","Run RSSHub behind a non-flagged egress IP; public instances are commonly risk-controlled.","Patch the throw to include the code so empty upstream messages stay diagnosable."],"tags":["bilibili","api-error","anti-crawler","ranking","rsshub"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}