jackwener/OpenCLI · error · CommandExecutionError

Cannot resolve aid for bvid: ${bvid}

Error message

Cannot resolve aid for bvid: ${bvid}

What it means

After resolving the BV id, the CLI calls /x/web-interface/view to map bvid → aid, which the reply API requires as `oid`. If the payload parses but lacks `aid`, the library throws CommandExecutionError since it cannot address the video.

Source

Thrown at clis/bilibili/comment.js:55

        if (!message)
            throw new ArgumentError('bilibili comment message cannot be empty');
        // Write guard: posting is public and irreversible-ish, so require an explicit opt-in.
        if (!kwargs.execute)
            throw new ArgumentError('Refusing to post: pass --execute to actually publish this comment');
        const parent = kwargs.parent != null ? readPositiveInteger(kwargs.parent, 'parent') : null;
        let bvid;
        try {
            bvid = await resolveBvid(kwargs.bvid);
        }
        catch (error) {
            throw new ArgumentError(`Cannot resolve Bilibili BV ID from input: ${String(kwargs.bvid ?? '')}`, error instanceof Error ? error.message : String(error));
        }
        // Resolve bvid → aid (the reply API addresses videos by aid, as `oid`)
        const view = await apiGet(page, '/x/web-interface/view', { params: { bvid } });
        const viewData = requireOkPayload(view, 'view');
        const oid = viewData?.aid;
        if (!oid)
            throw new CommandExecutionError(`Cannot resolve aid for bvid: ${bvid}`);
        // Resolve @username mentions to uids. Bilibili only turns "@name" into a real
        // mention — one that notifies the mentioned user — when the request carries
        // at_name_to_mid; a plain-text "@name" is otherwise inert and notifies nobody.
        /** @type {Record<string, number>} */
        const atNameToMid = {};
        for (const match of message.matchAll(/@([^\s@]+)/g)) {
            const name = match[1];
            if (name in atNameToMid)
                continue;
            try {
                const mid = Number(await resolveUid(page, name));
                if (!Number.isInteger(mid) || mid <= 0) {
                    throw new CommandExecutionError(`Bilibili user search returned malformed mid for @${name}`);
                }
                atNameToMid[name] = mid;
            }
            catch (error) {
                if (!(error instanceof EmptyResultError)) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the video is publicly accessible (open the bvid URL in a browser)
  2. Re-run later — transient API inconsistencies often resolve
  3. Check for Bilibili API schema changes and update the CLI
  4. Inspect the raw view API response for the bvid to confirm the aid field

Example fix

// before
const oid = viewData?.aid;
// after
const oid = viewData?.aid ?? viewData?.id; // handle schema variants
if (!oid) console.error('view payload:', JSON.stringify(viewData).slice(0, 200));
Defensive patterns

Strategy: validation

Validate before calling

const view = await fetch(`https://api.bilibili.com/x/web-interface/view?bvid=${bvid}`).then(r => r.json());
if (!view?.data?.aid) throw new Error(`No aid available for ${bvid}; video may be gone or region-locked`);

Type guard

const hasAid = (d) => d != null && typeof d.aid === 'number' && d.aid > 0;

Try / catch

try { await commentCmd(); } catch (e) { if (String(e.message).includes('Cannot resolve aid')) { console.error('Verify the video is public and retry'); } else throw e; }

Prevention

When it happens

Trigger: requireOkPayload succeeds on /x/web-interface/view but viewData.aid is missing/0 — e.g. unexpected API response shape, region-locked or deleted video, or Bilibili schema change.

Common situations: Video removed or made region-private so view payload lacks aid; Bilibili API field rename; response intercepted by anti-bot page returning valid JSON without aid.

Related errors


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