{"record":{"id":"20651c1ab9f2e51f","repo":"jackwener/OpenCLI","slug":"bilibili-conclusion-api-returned-malformed-model-r","errorCode":null,"errorMessage":"Bilibili conclusion API returned malformed model_result JSON","messagePattern":"Bilibili conclusion API returned malformed model_result JSON","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/summary.js","lineNumber":84,"sourceCode":"        }\n        throw new CommandExecutionError(`Bilibili ${label} API failed: ${message} (${payload.code})`);\n    }\n    return payload.data;\n}\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 }];","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/summary.js#L66-L102","documentation":"readModelResult parses the model_result field of Bilibili's video conclusion API response. When model_result arrives as a string (common, since the API returns it JSON-encoded), the function attempts JSON.parse; if parsing fails it throws this CommandExecutionError because the payload cannot be interpreted as the expected summary object.","triggerScenarios":"The /x/web-interface/view/conclusion/get endpoint returned HTTP 200 with code 0, but its model_result field is a string that is not valid JSON — e.g. truncated response, HTML injected by an anti-bot page, or an empty/placeholder string.","commonSituations":"Bilibili A/B testing a new response shape; requests made without a proper browser session/cookies so the API returns a degraded or CAPTCHA-laced body; network proxies mangling the response body; videos for which the AI summary feature returns non-standard content.","solutions":["Retry the conclusion request in the logged-in browser session — malformed payloads are often transient or anti-bot artifacts.","Log the raw model_result string before parsing to confirm what the API actually returned.","Verify the request is made through a real page context (apiGet with page) with valid cookies rather than a bare HTTP client.","Check that requireOkPayload succeeded and you are reading the right payload (view conclusion, not view details).","Guard the parse yourself before calling, treating parse failure as 'summary unavailable' rather than a crash."],"exampleFix":"// before\ntry {\n    modelResult = JSON.parse(modelResult);\n} catch {\n    throw new CommandExecutionError('Bilibili conclusion API returned malformed model_result JSON');\n}\n// after\ntry {\n    modelResult = JSON.parse(modelResult);\n} catch (err) {\n    console.error('model_result was:', data.model_result);\n    return null; // treat as summary unavailable instead of throwing\n}","handlingStrategy":"try-catch","validationCode":"if (typeof data.model_result === 'string' && data.model_result.trim()) {\n    try { JSON.parse(data.model_result); } catch { console.warn('model_result is not valid JSON'); }\n}","typeGuard":"function isParsableObject(v) {\n  if (typeof v !== 'string') return v !== null && typeof v === 'object' && !Array.isArray(v);\n  try { const p = JSON.parse(v); return p !== null && typeof p === 'object' && !Array.isArray(p); } catch { return false; }\n}","tryCatchPattern":"try {\n  const model = await readModelResult(page, bvid);\n} catch (e) {\n  if (String(e.message).includes('malformed model_result JSON')) {\n    console.warn('Skipping video: malformed summary payload');\n  } else throw e;\n}","preventionTips":["Use a real logged-in browser session so the API returns full payloads","Log raw API bodies when debugging rather than guessing the shape","Retry transient malformed responses before giving up","Treat AI-summary absence as a normal outcome, not a crash"],"tags":["bilibili","json-parse","api-response","validation"],"backgroundTag":"malformed-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}