jackwener/OpenCLI · error · CommandExecutionError

Bilibili conclusion API returned malformed outline section

Error message

Bilibili conclusion API returned malformed outline section

What it means

rowsFromModel iterates model.outline and validates each section is a non-null, non-array object before reading its title/timestamp. A section failing this check triggers this CommandExecutionError, protecting downstream String(section.title) and property access from crashes on nulls or scalars.

Solutions

  1. Log the offending outline section (JSON.stringify) to identify the bad entry.
  2. Filter invalid sections instead of throwing: outline.filter(s => s && typeof s === 'object' && !Array.isArray(s)).
  3. Retry the conclusion request — malformed sections can be transient on Bilibili's side.
  4. Validate the whole outline shape right after fetching, before calling rowsFromModel.
  5. Check whether Bilibili introduced a new section schema your parser mis-maps.

Example fix

// before
for (const section of model.outline) {
    if (!section || typeof section !== 'object' || Array.isArray(section)) {
        throw new CommandExecutionError('Bilibili conclusion API returned malformed outline section');
    }
// after
for (const section of model.outline) {
    if (!section || typeof section !== 'object' || Array.isArray(section)) {
        console.warn('skipping malformed outline section', section);
        continue;
    }
Defensive patterns

Strategy: validation

Validate before calling

const validSections = (model?.outline ?? []).filter(
  s => s && typeof s === 'object' && !Array.isArray(s)
);
if (validSections.length !== (model?.outline ?? []).length) console.warn('some outline sections invalid');

Type guard

function isOutlineSection(s) {
  return !!s && typeof s === 'object' && !Array.isArray(s);
}

Try / catch

try {
  const rows = rowsFromModel(model);
} catch (e) {
  if (String(e.message).includes('malformed outline section')) {
    return [{ time: '', content: model.summary }];
  }
  throw e;
}

Prevention

When it happens

Trigger: An outline array contains a null element, a string/number, or a nested array — e.g. Bilibili emitted a placeholder entry, or the outline was constructed/deserialized incorrectly upstream.

Common situations: Partially generated AI outlines for new videos; API responses with sentinel null entries; custom pipelines feeding hand-parsed model objects into rowsFromModel.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at clis/bilibili/summary.js:105

    if (!modelResult || typeof modelResult !== 'object' || Array.isArray(modelResult)) {
        throw new CommandExecutionError('Bilibili conclusion API returned malformed model_result');
    }
    const summary = String(modelResult.summary ?? '').trim();
    if (!summary) {
        throw new EmptyResultError('bilibili summary', `Bilibili has not generated an AI summary for ${bvid}.`);
    }
    const outline = modelResult.outline ?? [];
    if (!Array.isArray(outline)) {
        throw new CommandExecutionError('Bilibili conclusion API returned malformed outline');
    }
    return { summary, outline };
}

function rowsFromModel(model) {
    const rows = [{ time: '', content: model.summary }];
    for (const section of model.outline) {
        if (!section || typeof section !== 'object' || Array.isArray(section)) {
            throw new CommandExecutionError('Bilibili conclusion API returned malformed outline section');
        }
        const sectionTitle = String(section.title ?? '').trim();
        const sectionTime = formatTime(section.timestamp);
        if (sectionTitle) {
            rows.push({ time: sectionTime, content: `# ${sectionTitle}` });
        }
        const points = section.part_outline ?? [];
        if (!Array.isArray(points)) {
            throw new CommandExecutionError('Bilibili conclusion API returned malformed part outline');
        }
        for (const point of points) {
            if (!point || typeof point !== 'object' || Array.isArray(point)) {
                throw new CommandExecutionError('Bilibili conclusion API returned malformed outline point');
            }
            const content = String(point.content ?? '').trim();
            if (content) {
                rows.push({ time: formatTime(point.timestamp), content });
            }

View on GitHub (pinned to 49907e53dc)