jackwener/OpenCLI · error · CommandExecutionError

Bilibili view API returned a malformed pages[] entry

Error message

Bilibili view API returned a malformed pages[] entry

What it means

Each entry in the view API's pages[] array must be a non-null, non-array object so its page/cid fields can be read. selectVideoPart throws this fail-closed error when any entry is null, a primitive, or an array, since a malformed entry could cause the wrong part to be selected silently.

Source

Thrown at clis/bilibili/utils.js:124

        if (Number.isSafeInteger(n)) return n;
    }
    throw new CommandExecutionError(`Bilibili view API returned a malformed ${label}`);
}

/**
 * 从 view API 的 data.pages 数组取第 N 集(1-based)。
 * page/cid 都以 view API 的 pages[] 为 source-of-truth;缺失、重复或畸形都 fail closed。
 * 返回该集 raw 对象(含 cid / part(分集标题) / page / duration)。
 */
export function selectVideoPart(viewData, pageNum) {
    const pages = Array.isArray(viewData?.pages) ? viewData.pages : null;
    if (!pages || pages.length === 0) {
        throw new CommandExecutionError('Bilibili view API did not return pages[] for --page selection');
    }
    const matches = [];
    for (const entry of pages) {
        if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
            throw new CommandExecutionError('Bilibili view API returned a malformed pages[] entry');
        }
        const apiPage = readApiPositiveInteger(entry.page, 'page number');
        if (apiPage === pageNum) {
            matches.push(entry);
        }
    }
    if (matches.length > 1) {
        throw new CommandExecutionError(`Bilibili view API returned duplicate page entries for p=${pageNum}`);
    }
    const part = matches[0];
    if (!part) {
        const total = pages.length || viewData?.videos || 1;
        throw new CommandExecutionError(`分P 序号超出范围:p=${pageNum}(该视频共 ${total} 集)`);
    }
    readApiPositiveInteger(part.cid, `cid for p=${pageNum}`);
    return part;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-fetch the view API response — corrupted payloads are often transient.
  2. Log the raw response body and inspect the offending pages[] element.
  3. Verify you are calling the official /x/web-interface/view endpoint, not a mirror/proxy that alters JSON.
  4. If the schema changed, update selectVideoPart in clis/bilibili/utils.js to match the new shape.

Example fix

// before
const pages = viewData.pages; // may contain null or junk entries
// after
const pages = (viewData?.pages ?? []).filter(
  (e) => e && typeof e === 'object' && !Array.isArray(e) && typeof e.page === 'number'
);
Defensive patterns

Strategy: type-guard

Validate before calling

const cleanPages = (viewData?.pages ?? []).filter(e => e && typeof e==='object' && !Array.isArray(e));
if (cleanPages.length !== (viewData?.pages ?? []).length) console.warn('corrupt pages[] entries dropped');

Type guard

function isPageEntry(e){ return !!e && typeof e==='object' && !Array.isArray(e) && typeof e.page!=='undefined' && typeof e.cid!=='undefined'; }

Try / catch

try { const part = selectVideoPart(viewData, pageNum); } catch (e) { if (/malformed pages/.test(e.message)) { logRawResponse(viewData); throw new Error('Bilibili returned corrupt pages[]; inspect payload'); } throw e; }

Prevention

When it happens

Trigger: Iterating viewData.pages and encountering an entry that is null, undefined, a number/string/boolean, or an Array — i.e., Bilibili returned a structurally corrupt pages[] list.

Common situations: Bilibili API incidents returning degraded JSON; intermediary proxies mangling the response; schema drift where pages contains unexpected element shapes; hand-written test fixtures with wrong element types.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/eb3222ba0f6ff825. Report an issue: GitHub.