jackwener/OpenCLI · error · CommandExecutionError

Pixiv novel ${id} returned malformed content payload

Error message

Pixiv novel ${id} returned malformed content payload

What it means

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.

Source

Thrown at clis/pixiv/novel-download-utils.js:24

function optionalDownloadCount(value, label) {
  if (value == null || value === '') return null;
  if (!Number.isSafeInteger(value) || value < 0) {
    throw new CommandExecutionError(`Pixiv novel ${label} returned malformed data`);
  }
  return value;
}

function requireNovelDownloadBody(body, id) {
  if (!body || Array.isArray(body) || typeof body !== 'object') {
    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);
  }
  const novelId = String(body.id ?? '').trim();
  const title = typeof body.title === 'string' ? body.title.trim() : '';
  const author = typeof body.userName === 'string' ? body.userName.trim() : '';
  const userId = String(body.userId ?? '').trim();
  if (typeof body.content !== 'string') {
    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed content payload`);
  }
  if (!/^\d+$/.test(novelId) || novelId !== id || !title || !author || !/^\d+$/.test(userId)) {
    throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);
  }
  // Validate metadata before any file is planned or created.
  tagsToString(body.tags);
  const createdDate = dateOnly(body.createDate);
  const wordCount = optionalDownloadCount(body.wordCount, 'word count');
  const bookmarkCount = optionalDownloadCount(body.bookmarkCount, 'bookmark count');
  return {
    ...body,
    id: novelId,
    title,
    userName: author,
    userId,
    content: body.content,
    createdDate,
    wordCount,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Confirm your session can view the full novel (login, R-18 settings, my-pixiv access)
  2. Check the raw response to see what type content actually is
  3. Retry in case of a transient bad payload
  4. Update parsing if pixiv changed the content field format
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof body.content !== 'string') {
  throw new Error(`Novel ${id}: content missing or non-string (access restricted?)`);
}

Type guard

const hasStringContent = (b) => typeof b?.content === 'string';

Try / catch

try {
  await novelDownload(id);
} catch (e) {
  if (/malformed content payload/.test(e.message)) {
    console.warn(`Novel ${id} not fully accessible with current session`);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/cfecb0fb55ad58bd. Report an issue: GitHub.