{"record":{"id":"d26d7df255bc64e8","repo":"jackwener/OpenCLI","slug":"label-returned-a-malformed-string","errorCode":null,"errorMessage":"${label} returned a malformed string","messagePattern":"(.+?) returned a malformed string","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/bilibili/video.js","lineNumber":29,"sourceCode":"\nfunction unwrapBrowserResult(value) {\n  if (value && typeof value === 'object' && typeof value.session === 'string' && Object.hasOwn(value, 'data')) {\n    return value.data;\n  }\n  return value;\n}\n\nfunction readOptionalFlag(value, label) {\n  if (value == null) return false;\n  if (typeof value === 'boolean') return value;\n  if (typeof value === 'number') return value !== 0;\n  throw new CommandExecutionError(`${label} returned a malformed flag`);\n}\n\nfunction readOptionalString(value, label) {\n  if (value == null) return '';\n  if (typeof value === 'string') return value;\n  throw new CommandExecutionError(`${label} returned a malformed string`);\n}\n\ncli({\n  site: 'bilibili',\n  name: 'video',\n    access: 'read',\n  description: 'Get Bilibili video metadata (title, author, duration, stats, etc.)',\n  strategy: Strategy.COOKIE,\n  args: [\n    { name: 'bvid', required: true, positional: true, help: 'BV ID, video URL, or b23.tv short link' },\n    { name: 'page', required: false, help: '分P 选集序号（从 1 开始）。多 P 视频指定某一集，title/cid 返回该集；缺省取整集默认（P1）' },\n  ],\n  columns: ['field', 'value'],\n  func: async (page, kwargs) => {\n    if (!page) {\n      throw new CommandExecutionError('Browser session required for bilibili video');\n    }\n","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/bilibili/video.js#L11-L47","documentation":"readOptionalString validates that an optional string field is null/undefined or a string; anything else throws this CommandExecutionError. It is used by the redirectUrl accessor of the bilibili video command.","triggerScenarios":"The video API's redirect_url (or similar string field) arrives as a number, object, or array instead of a string — schema drift or an unusual video entry shape.","commonSituations":"Bilibili changing a field's type; certain videos (deleted, region-locked) returning structured error objects where a string is expected; middleware JSON transformations.","solutions":["Log the raw value for the failing video to see the unexpected type","Coerce safe cases (e.g. String(value)) if the field is reliably scalar","Catch the error and return '' for redirect_url so the rest of the output still renders","Update the field handling in clis/bilibili/video.js if the API schema changed"],"exampleFix":"// before\nif (typeof value === 'string') return value;\nthrow new CommandExecutionError(`${label} returned a malformed string`);\n// after\nif (typeof value === 'string') return value;\nif (typeof value === 'number') return String(value);\nthrow new CommandExecutionError(`${label} returned a malformed string`);","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"function isOptionalString(v) {\n  return v == null || typeof v === 'string';\n}","tryCatchPattern":"try { const info = await getVideoInfo(bvid); }\ncatch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('malformed string')) { console.warn('redirect_url had unexpected type'); }\n  else throw e;\n}","preventionTips":["Never assume string fields are always strings in scraped payloads","Coerce scalars defensively at the parsing boundary","Regression-test against captured real payloads","Handle deleted/locked videos where fields may become structured errors"],"tags":["type-mismatch","api","bilibili"],"backgroundTag":"unexpected-field-type","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}