{"record":{"id":"da54d91939f5c60d","repo":"jackwener/OpenCLI","slug":"bilibili-conclusion-api-returned-malformed-outline-da54d9","errorCode":null,"errorMessage":"Bilibili conclusion API returned malformed outline section","messagePattern":"Bilibili conclusion API returned malformed outline section","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/summary.js","lineNumber":105,"sourceCode":"    if (!modelResult || typeof modelResult !== 'object' || Array.isArray(modelResult)) {\n        throw new CommandExecutionError('Bilibili conclusion API returned malformed model_result');\n    }\n    const summary = String(modelResult.summary ?? '').trim();\n    if (!summary) {\n        throw new EmptyResultError('bilibili summary', `Bilibili has not generated an AI summary for ${bvid}.`);\n    }\n    const outline = modelResult.outline ?? [];\n    if (!Array.isArray(outline)) {\n        throw new CommandExecutionError('Bilibili conclusion API returned malformed outline');\n    }\n    return { summary, outline };\n}\n\nfunction rowsFromModel(model) {\n    const rows = [{ time: '', content: model.summary }];\n    for (const section of model.outline) {\n        if (!section || typeof section !== 'object' || Array.isArray(section)) {\n            throw new CommandExecutionError('Bilibili conclusion API returned malformed outline section');\n        }\n        const sectionTitle = String(section.title ?? '').trim();\n        const sectionTime = formatTime(section.timestamp);\n        if (sectionTitle) {\n            rows.push({ time: sectionTime, content: `# ${sectionTitle}` });\n        }\n        const points = section.part_outline ?? [];\n        if (!Array.isArray(points)) {\n            throw new CommandExecutionError('Bilibili conclusion API returned malformed part outline');\n        }\n        for (const point of points) {\n            if (!point || typeof point !== 'object' || Array.isArray(point)) {\n                throw new CommandExecutionError('Bilibili conclusion API returned malformed outline point');\n            }\n            const content = String(point.content ?? '').trim();\n            if (content) {\n                rows.push({ time: formatTime(point.timestamp), content });\n            }","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/summary.js#L87-L123","documentation":"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.","triggerScenarios":"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.","commonSituations":"Partially generated AI outlines for new videos; API responses with sentinel null entries; custom pipelines feeding hand-parsed model objects into rowsFromModel.","solutions":["Log the offending outline section (JSON.stringify) to identify the bad entry.","Filter invalid sections instead of throwing: outline.filter(s => s && typeof s === 'object' && !Array.isArray(s)).","Retry the conclusion request — malformed sections can be transient on Bilibili's side.","Validate the whole outline shape right after fetching, before calling rowsFromModel.","Check whether Bilibili introduced a new section schema your parser mis-maps."],"exampleFix":"// before\nfor (const section of model.outline) {\n    if (!section || typeof section !== 'object' || Array.isArray(section)) {\n        throw new CommandExecutionError('Bilibili conclusion API returned malformed outline section');\n    }\n// after\nfor (const section of model.outline) {\n    if (!section || typeof section !== 'object' || Array.isArray(section)) {\n        console.warn('skipping malformed outline section', section);\n        continue;\n    }","handlingStrategy":"validation","validationCode":"const validSections = (model?.outline ?? []).filter(\n  s => s && typeof s === 'object' && !Array.isArray(s)\n);\nif (validSections.length !== (model?.outline ?? []).length) console.warn('some outline sections invalid');","typeGuard":"function isOutlineSection(s) {\n  return !!s && typeof s === 'object' && !Array.isArray(s);\n}","tryCatchPattern":"try {\n  const rows = rowsFromModel(model);\n} catch (e) {\n  if (String(e.message).includes('malformed outline section')) {\n    return [{ time: '', content: model.summary }];\n  }\n  throw e;\n}","preventionTips":["Filter outline sections to objects before iterating","Log offending entries instead of failing the whole render","Retry once on malformed payloads before giving up","Sanitize API data at fetch time, not render time"],"tags":["bilibili","schema-validation","outline","data-mapping"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}