jackwener/OpenCLI · error · CommandExecutionError
Bilibili view API returned malformed paid-content metadata
Error message
Bilibili view API returned malformed paid-content metadata
What it means
The view API returned code 0 (success) but payload.data or payload.data.rights is not an object, so payment rights (pay, ugc_pay, arc_pay, is_upower_exclusive) cannot be read. The library throws rather than silently treating the video as free, since rights info is the whole point of the pre-check.
Source
Thrown at clis/bilibili/download.js:44
/**
* 下载前付费预检:付费/会员视频 yt-dlp 只能拿到试看流或直接失败,
* 与其跑一半吐一坨 yt-dlp stderr,不如提前抛结构化 PAID_CONTENT(exit 77)。
*
* 大会员专享(vip)会再查一次 nav API:当前账号大会员有效就放行(cookie 喂给
* yt-dlp 能下完整流)。ugc_pay / upower 的购买/充电状态没有廉价查询端点,保守
* 拦截,已购用户用 --force 跳过。预检自身的 API 失败不阻塞下载(保持旧行为)。
*/
async function assertNotPaidContent(page, bvid) {
let d;
try {
const payload = await apiGet(page, '/x/web-interface/view', { params: { bvid } });
if (!isObject(payload) || !Object.hasOwn(payload, 'code')) {
throw new CommandExecutionError('Bilibili view API returned a malformed payload during paid-content pre-check');
}
if (payload.code !== 0)
return;
if (!isObject(payload.data) || !isObject(payload.data.rights)) {
throw new CommandExecutionError('Bilibili view API returned malformed paid-content metadata');
}
d = payload.data;
}
catch (error) {
if (error instanceof CommandExecutionError) {
throw error;
}
return;
}
const rights = d.rights;
const paymentType = rights.pay
? 'vip'
: (rights.ugc_pay || rights.arc_pay)
? 'ugc_pay'
: d.is_upower_exclusive
? 'upower'
: '';
if (!paymentType)View on GitHub (pinned to 49907e53dc)
Solutions
- Retry; if intermittent it's a partial response, not a schema change.
- If the video is known-paid and you have entitlement, use --force to skip the pre-check entirely.
- Fetch the raw view API response to confirm whether data.rights exists; if Bilibili moved it, the CLI needs an update.
- Try a different bvid to determine if it is content-type-specific.
Example fix
// caller-side guard
const payload = await apiGet(page, '/x/web-interface/view', { params: { bvid } });
const rights = payload?.data?.rights;
if (payload?.code === 0 && (!rights || typeof rights !== 'object' || Array.isArray(rights))) {
// fall back to --force download or retry
} Defensive patterns
Strategy: type-guard
Validate before calling
const payload = JSON.parse(await (await fetch(viewApiUrl, { headers: { cookie } })).text());
if (payload?.code === 0 && (!(payload.data?.rights) || typeof payload.data.rights !== 'object')) {
// rights unavailable: skip pre-check with --force or retry
} Type guard
function hasRights(payload) {
return Boolean(payload?.data) && typeof payload.data === 'object' && !Array.isArray(payload.data)
&& Boolean(payload.data.rights) && typeof payload.data.rights === 'object';
} Try / catch
try {
await download(bvid);
} catch (e) {
if (/malformed paid-content metadata/.test(e.message)) {
// fall back to --force if you hold entitlement, or retry
} else throw e;
} Prevention
- Use --force for content types known to omit rights (courses, charging-exclusive)
- Retry intermittent partial responses before concluding schema drift
- Verify data.rights in the raw view API when debugging
- Update the CLI when Bilibili relocates the rights object
When it happens
Trigger: /x/web-interface/view responds with code:0 but data or data.rights is missing/null/non-object — seen with partial responses from Bilibili, A/B schema rollouts, or special archive types (courses, charging-exclusive) that omit the rights object.
Common situations: Downloading charging-exclusive (充电专属) or course content whose view payload lacks standard rights; Bilibili API drift; intermittent partial responses under load.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Bilibili ${label} API returned malformed top_replies
- Bilibili creator comparison returned malformed stat data for
- Bilibili comments reply ${index + 1} was malformed
- Bilibili comments reply ${index + 1} was missing rpid
- Bilibili comments reply ${index + 1} was missing ctime
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/eb927bb17baa6115.
Report an issue: GitHub.