DIYgod/RSSHub · error
response.message ?? `Error code ${response.code}`
Error message
response.message ?? `Error code ${response.code}` What it means
Thrown by the bilibili message-like route after the authenticated request to https://api.bilibili.com/x/msgfeed/like succeeds at the HTTP layer but returns a non-zero business `code`. Bilibili APIs always answer 200 OK with a JSON body whose `code` field signals success (0) or failure (negative); when code !== 0 the route raises a plain Error carrying the upstream `message` (or a fallback 'Error code N'). It means the cookie was present and accepted by the network, but Bilibili rejected the call at the application layer.
Source
Thrown at lib/routes/bilibili/message-like.ts:114
const cookie = config.bilibili.cookies[uid];
if (cookie === undefined) {
throw new ConfigNotFoundError('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
}
const response = await ofetch<LikeResponse>('https://api.bilibili.com/x/msgfeed/like', {
query: {
platform: 'web',
build: 0,
mobi_app: 'web',
},
headers: {
Referer: 'https://message.bilibili.com/',
Cookie: cookie,
},
});
if (response.code !== 0) {
throw new Error(response.message ?? `Error code ${response.code}`);
}
const allItems = [...(response.data.latest?.items || []), ...(response.data.total?.items || [])];
// Deduplicate by id
const uniqueItems = allItems.filter((item, index, self) => index === self.findIndex((t) => t.id === item.id));
const items: DataItem[] = uniqueItems.map((item) => {
const likeUsers = item.users;
const likeItem = item.item;
const counts = item.counts;
const userNames = likeUsers.map((u) => u.nickname).join('、');
const displayNames = counts > likeUsers.length ? `${userNames} 等 ${counts} 人` : userNames;
let description = `<p><strong>${displayNames}</strong> 赞了你的${likeItem.business}:</p>`;
description += `<p><strong>${likeItem.title}</strong></p>`;
View on GitHub (pinned to bed535e087)
Solutions
- Refresh the cookie: log in to bilibili.com in a clean browser session, re-copy the full Cookie header (including SESSDATA, bili_jct, DedeUserID), and update BILIBILI_COOKIE_{uid}.
- Check the numeric code in the error text: -101 means not-logged-in (cookie invalid), -352/-799 means risk control (slow down or use a different account), -403 means permission denied.
- Reduce polling frequency in your RSS reader (e.g. interval >= 10 min) to avoid tripping Bilibili's rate/risk limits.
- Verify the cookie's DedeUserID matches the uid in the route path.
Example fix
// before
const response = await ofetch<LikeResponse>(URL, { headers: { Cookie: cookie } });
if (response.code !== 0) {
throw new Error(response.message ?? `Error code ${response.code}`);
}
// after (classify known auth failures for clearer UX)
if (response.code !== 0) {
if (response.code === -101) {
throw new ConfigNotFoundError(`Bilibili cookie for uid ${uid} is invalid or expired (code -101)`);
}
throw new Error(response.message ?? `Error code ${response.code}`);
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: verify the cookie still authenticates before serving the feed.
import ofetch from '@/utils/ofetch';
import { config } from '@/config';
async function isBilibiliCookieValid(uid: string): Promise<boolean> {
const cookie = config.bilibili.cookies[uid];
if (!cookie) return false;
try {
const nav = await ofetch<{ code: number }>('https://api.bilibili.com/x/web-interface/nav', {
headers: { Cookie: cookie },
});
return nav.code === 0; // -101 means expired/invalid
} catch {
return false;
}
} Type guard
// Narrow a Bilibili API response into success vs failure.
interface BiliEnvelope<T> { code: number; message?: string; data?: T }
function isBiliSuccess<T>(r: BiliEnvelope<T>): r is BiliEnvelope<T> & { code: 0; data: T } {
return r.code === 0;
} Try / catch
try {
const response = await ofetch<LikeResponse>(URL, { headers: { Cookie: cookie } });
if (response.code !== 0) throw new Error(response.message ?? `Error code ${response.code}`);
// ...
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (msg.includes('-101')) {
// cookie expired -> surface a config-refresh hint, do NOT retry blindly
throw new Error(`BILIBILI_COOKIE_${uid} expired; please refresh it.`);
}
if (msg.includes('-352') || msg.includes('-799')) {
// transient risk control -> safe to retry with backoff
await backoffRetry(() => ofetch(URL, opts));
}
throw e;
} Prevention
- Periodically validate each BILIBILI_COOKIE_* against the /x/web-interface/nav endpoint and alert when it starts returning -101.
- Cache the msgfeed/like response for a few minutes (cache.tryGet) to avoid hammering Bilibili on every reader poll.
- Keep RSS reader poll intervals >= 10 minutes to stay below Bilibili's risk-control threshold.
- Store the cookie's DedeUserID alongside the env var and assert it matches the route uid.
When it happens
Trigger: GET /bilibili/message/like/:uid where the configured BILIBILI_COOKIE_{uid} is expired, revoked, or belongs to a restricted account, so msgfeed/like returns code -101 (账号未登录) or -352 (风控校验). Also triggered when the uid in the path does not match the account the cookie belongs to.
Common situations: SESSDATA expired (Bilibili rotates it on password change / security events); cookie copied without the bili_jct / DedeUserID fields; account hit by anti-crawler risk control from too many RSSHub polls; bilibili changed the msgfeed/like response contract.
Related errors
- response.message ?? `Error code ${response.code}`
- response.message ?? response.msg ?? `Error code ${response.c
- response.message ?? response.msg ?? `Error code ${response.c
- msgUnread.message ?? `Error code ${msgUnread.code}`
- It looks like something went wrong when querying the Bilibil
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/4fa590c30022c6f8.
Report an issue: GitHub.