{"record":{"id":"af906e684701ec16","repo":"jackwener/OpenCLI","slug":"commandname-malformed-comment-row-image-url","errorCode":null,"errorMessage":"${commandName}: malformed comment row image URL","messagePattern":"(.+?): malformed comment row image URL","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/comments.js","lineNumber":85,"sourceCode":"function normalizeOptionalString(value, field, commandName) {\n    if (value == null)\n        return '';\n    if (typeof value !== 'string') {\n        throw new CommandExecutionError(`${commandName}: malformed comment row ${field}`);\n    }\n    return value;\n}\n\nexport function normalizeCommentImages(value, commandName) {\n    if (value == null)\n        return [];\n    if (!Array.isArray(value)) {\n        throw new CommandExecutionError(`${commandName}: malformed comment row images`);\n    }\n    const urls = [];\n    for (const raw of value) {\n        if (typeof raw !== 'string') {\n            throw new CommandExecutionError(`${commandName}: malformed comment row image URL`);\n        }\n        const trimmed = raw.trim();\n        let parsed;\n        try {\n            parsed = new URL(trimmed);\n        }\n        catch {\n            throw new CommandExecutionError(`${commandName}: malformed comment row image URL`);\n        }\n        if ((parsed.protocol !== 'https:' && parsed.protocol !== 'http:') || parsed.username || parsed.password) {\n            throw new CommandExecutionError(`${commandName}: malformed comment row image URL`);\n        }\n        const href = parsed.toString();\n        if (!urls.includes(href))\n            urls.push(href);\n    }\n    return urls;\n}","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/comments.js#L67-L103","documentation":"Each entry in a comment row's images array must be a string URL. A non-string element (number, object, null item) throws this CommandExecutionError because the URL cannot be parsed safely.","triggerScenarios":"The images array contains a non-string element, e.g. an image descriptor object { url, width } instead of the plain URL string.","commonSituations":"XHS payload drift to structured image objects, or caller mapping rows incorrectly and pushing objects into the images array.","solutions":["Inspect the array element that is not a string and map it to its url property before normalizing.","Add a pre-parse step converting image objects to their URL strings.","Update normalizeCommentImages to accept {url}-style objects.","Validate each element with typeof === 'string' before calling the API."],"exampleFix":"// before\nnormalizeCommentImages(row.images, cmd);\n// after\nconst imgs = (row.images ?? []).map(i => typeof i === 'string' ? i : i?.url);\nnormalizeCommentImages(imgs, cmd);","handlingStrategy":"type-guard","validationCode":"const bad = (row.images ?? []).filter(i => typeof i !== 'string');\nif (bad.length) throw new Error(`${bad.length} non-string image entries`);","typeGuard":"function isStringArray(v) {\n  return Array.isArray(v) && v.every(x => typeof x === 'string');\n}","tryCatchPattern":"try {\n  urls = normalizeCommentImages(row.images, cmd);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /image URL/.test(e.message)) {\n    urls = [];\n  } else throw e;\n}","preventionTips":["Map structured image objects to their url string before normalizing.","Filter non-string entries out of scraped image arrays.","Log the offending element (index/type) when this fires.","Keep extraction code returning plain URL strings, not descriptors."],"tags":["validation","url","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}