jackwener/OpenCLI · error · CommandExecutionError

Pixiv user profile returned malformed novels payload

Error message

Pixiv user profile returned malformed novels payload

What it means

requireProfileNovelIds validates the Pixiv user profile response's novels field: it must be a non-null, non-array object (a map of novelId -> data). If novels is missing/null, is an array, or is a non-object primitive, the library throws because the profile payload shape is unusable for enumerating novel IDs. This guards against Pixiv schema changes or error responses being parsed as a valid profile.

Source

Thrown at clis/pixiv/novels.js:44

  }
  const title = requirePixivString(item.title, 'Pixiv user novel item');
  return {
    rank,
    title,
    novel_id: id,
    words: optionalCount(item.wordCount, 'word count'),
    characters: optionalCount(item.textCount ?? item.characterCount, 'character count'),
    bookmarks: optionalCount(item.bookmarkCount, 'bookmark count', 0),
    tags: tagsToString(item.tags),
    created: dateOnly(item.createDate),
    url: `https://www.pixiv.net/novel/show.php?id=${id}`,
  };
}

function requireProfileNovelIds(body) {
  const payload = requirePixivPayloadObject(body, 'Pixiv user profile');
  if (!payload.novels || Array.isArray(payload.novels) || typeof payload.novels !== 'object') {
    throw new CommandExecutionError('Pixiv user profile returned malformed novels payload');
  }
  const ids = Object.keys(payload.novels);
  const invalid = ids.find(id => !/^\d+$/.test(id));
  if (invalid) {
    throw new CommandExecutionError(`Pixiv user profile returned malformed novel ID: ${invalid}`);
  }
  return ids;
}

function requireDetailWorks(body) {
  const payload = requirePixivPayloadObject(body, 'Pixiv user novel details');
  if (!payload.works || Array.isArray(payload.works) || typeof payload.works !== 'object') {
    throw new CommandExecutionError('Pixiv user novel details returned malformed works payload');
  }
  return payload.works;
}

cli({

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the full response body/status to see what actually came back (auth failure vs shape change)
  2. Handle the empty case before parsing: if the user has no novels, treat empty array/missing as zero results rather than an error
  3. Verify the target user ID is valid, public, and not deleted
  4. Check for rate-limit/login requirements (Pixiv may need cookies/PHPSESSID) and retry with valid auth
  5. Update the parser to accept both object-map and array forms of novels

Example fix

// before
const ids = requireProfileNovelIds(body);
// after
if (body && Array.isArray(body.novels)) {
  body.novels = Object.fromEntries(body.novels.map(n => [String(n.id), n]));
}
const ids = requireProfileNovelIds(body);
Defensive patterns

Strategy: validation

Validate before calling

function hasValidNovelsMap(body) {
  return body != null &&
    typeof body.novels === 'object' && body.novels !== null &&
    !Array.isArray(body.novels);
}
if (!hasValidNovelsMap(body)) throw new Error('Profile response unusable: novels is not an object map');

Type guard

function hasNovelsMap(p) {
  return typeof p === 'object' && p !== null &&
    typeof p.novels === 'object' && p.novels !== null && !Array.isArray(p.novels);
}
// usage: if (hasNovelsMap(profile)) { Object.keys(profile.novels) ... }

Try / catch

try {
  const ids = requireProfileNovelIds(body);
} catch (err) {
  if (String(err.message).includes('malformed novels payload')) {
    console.warn('No usable novels map (empty account, private user, or auth/rate-limit body); returning []');
    return [];
  }
  throw err;
}

Prevention

When it happens

Trigger: Pixiv profile endpoint returns {novels: null}, {novels: []}, {novels: '123'}, or omits novels entirely — often when the user has no novels, the user does not exist/is private, or the API returns an error/HTML page parsed loosely.

Common situations: Querying a user ID that has zero novels (API may return empty array instead of object); deleted or restricted accounts; rate-limit or auth-failure bodies being fed to the parser; Pixiv API version drift changing novels from map to list.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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