{"record":{"id":"8cab0ea6c3d7420e","repo":"jackwener/OpenCLI","slug":"bilibili-conclusion-api-returned-malformed-model-r-8cab0e","errorCode":null,"errorMessage":"Bilibili conclusion API returned malformed model_result","messagePattern":"Bilibili conclusion API returned malformed model_result","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/summary.js","lineNumber":88,"sourceCode":"}\n\nfunction readModelResult(data, bvid) {\n    if (!data || typeof data !== 'object' || Array.isArray(data)) {\n        throw new CommandExecutionError('Bilibili conclusion API returned malformed data');\n    }\n    if (data.code !== 0) {\n        throw new EmptyResultError('bilibili summary', `Bilibili has not generated an AI summary for ${bvid}.`);\n    }\n    let modelResult = data.model_result;\n    if (typeof modelResult === 'string') {\n        try {\n            modelResult = JSON.parse(modelResult);\n        } catch {\n            throw new CommandExecutionError('Bilibili conclusion API returned malformed model_result JSON');\n        }\n    }\n    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        }","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/summary.js#L70-L106","documentation":"After parsing (or when model_result is already an object), readModelResult validates that model_result is a non-null, non-array object. Bilibili's conclusion API can return model_result as null or an unexpected scalar when no AI summary exists; this CommandExecutionError signals the response shape is not the expected summary structure.","triggerScenarios":"model_result is null, a number/boolean, or an array — e.g. the conclusion endpoint returned code 0 but with an empty model_result, or the caller passed the wrong payload object into readModelResult.","commonSituations":"Videos without an AI conclusion where the API still returns code 0; API contract changes on Bilibili's side; accidentally passing the outer response or view payload instead of the conclusion payload.","solutions":["Check whether the video actually has an AI summary (try it in the Bilibili web UI) — absence is a valid API outcome, not necessarily a bug.","Log data.model_result and its typeof before the call to see the real shape.","Confirm you are passing the conclusion payload's model_result, not the whole response.","Handle null model_result as an empty-summary case in your own wrapper.","Update the client if Bilibili changed the response schema."],"exampleFix":"// before\nif (!modelResult || typeof modelResult !== 'object' || Array.isArray(modelResult)) {\n    throw new CommandExecutionError('Bilibili conclusion API returned malformed model_result');\n}\n// after\nif (!modelResult || typeof modelResult !== 'object' || Array.isArray(modelResult)) {\n    return null; // no AI summary for this video\n}","handlingStrategy":"type-guard","validationCode":"const mr = data?.model_result;\nconst ok = mr !== null && typeof mr === 'object' && !Array.isArray(mr);\nif (!ok) console.warn('no usable model_result for', bvid);","typeGuard":"function isModelResult(v) {\n  return v !== null && typeof v === 'object' && !Array.isArray(v) && typeof v.summary === 'string';\n}","tryCatchPattern":"try {\n  const model = await readModelResult(page, bvid);\n} catch (e) {\n  if (String(e.message).endsWith('malformed model_result')) return null;\n  throw e;\n}","preventionTips":["Pass the conclusion payload's model_result, not the outer response","Check the video has an AI summary in the web UI first","Validate payload shape right after fetching","Watch for Bilibili API schema changes"],"tags":["bilibili","api-response","schema-validation","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}