{"record":{"id":"cfecb0fb55ad58bd","repo":"jackwener/OpenCLI","slug":"pixiv-novel-id-returned-malformed-content-paylo","errorCode":null,"errorMessage":"Pixiv novel ${id} returned malformed content payload","messagePattern":"Pixiv novel (.+?) returned malformed content payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/pixiv/novel-download-utils.js","lineNumber":24,"sourceCode":"\nfunction optionalDownloadCount(value, label) {\n  if (value == null || value === '') return null;\n  if (!Number.isSafeInteger(value) || value < 0) {\n    throw new CommandExecutionError(`Pixiv novel ${label} returned malformed data`);\n  }\n  return value;\n}\n\nfunction requireNovelDownloadBody(body, id) {\n  if (!body || Array.isArray(body) || typeof body !== 'object') {\n    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);\n  }\n  const novelId = String(body.id ?? '').trim();\n  const title = typeof body.title === 'string' ? body.title.trim() : '';\n  const author = typeof body.userName === 'string' ? body.userName.trim() : '';\n  const userId = String(body.userId ?? '').trim();\n  if (typeof body.content !== 'string') {\n    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed content payload`);\n  }\n  if (!/^\\d+$/.test(novelId) || novelId !== id || !title || !author || !/^\\d+$/.test(userId)) {\n    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);\n  }\n  // Validate metadata before any file is planned or created.\n  tagsToString(body.tags);\n  const createdDate = dateOnly(body.createDate);\n  const wordCount = optionalDownloadCount(body.wordCount, 'word count');\n  const bookmarkCount = optionalDownloadCount(body.bookmarkCount, 'bookmark count');\n  return {\n    ...body,\n    id: novelId,\n    title,\n    userName: author,\n    userId,\n    content: body.content,\n    createdDate,\n    wordCount,","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/pixiv/novel-download-utils.js#L6-L42","documentation":"Thrown when the novel detail body is an object but its content field is not a string. The library requires body.content to be the novel text; any other type means a malformed or changed payload.","triggerScenarios":"Pixiv returns a detail object without 'content' (e.g. restricted preview payload), or the field arrives as an array/object due to an API change.","commonSituations":"Downloading a novel your session cannot fully access (R-18 or my-pixiv-only works) so content is omitted; pixiv schema changes; cached partial responses.","solutions":["Confirm your session can view the full novel (login, R-18 settings, my-pixiv access)","Check the raw response to see what type content actually is","Retry in case of a transient bad payload","Update parsing if pixiv changed the content field format"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if (typeof body.content !== 'string') {\n  throw new Error(`Novel ${id}: content missing or non-string (access restricted?)`);\n}","typeGuard":"const hasStringContent = (b) => typeof b?.content === 'string';","tryCatchPattern":"try {\n  await novelDownload(id);\n} catch (e) {\n  if (/malformed content payload/.test(e.message)) {\n    console.warn(`Novel ${id} not fully accessible with current session`);\n  } else throw e;\n}","preventionTips":["Ensure login and R-18/my-pixiv permissions cover the target novels","Check the raw payload type of content when this fires","Skip restricted works in bulk jobs","Re-authenticate when multiple novels fail the same way"],"tags":["api","validation","malformed-response"],"backgroundTag":"malformed-api-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}