jackwener/OpenCLI · error · CommandExecutionError

Pixiv novel ${label} returned malformed data

Error message

Pixiv novel ${label} returned malformed data

What it means

optionalDownloadCount validates pixiv's wordCount/bookmarkCount fields for a novel download. If the field is present but not a safe non-negative integer, it throws this CommandExecutionError, indicating the API returned data in an unexpected shape for that counter.

Source

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

import * as fs from 'node:fs';
import * as path from 'node:path';
import { ArgumentError, CommandExecutionError } from '@jackwener/opencli/errors';
import { pixivFetch } from './utils.js';
import { dateOnly, tagsToString } from './bookmark-utils.js';

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`);
  }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the raw /ajax/novel/{id} response to see the actual type of wordCount/bookmarkCount
  2. Re-fetch after a short delay in case of a transient bad response
  3. Update the parsing code to coerce numeric strings with Number() when pixiv changes types
  4. Pin/report the pixiv API behavior change in the tool's issue tracker

Example fix

// before
if (!Number.isSafeInteger(value) || value < 0) { throw ... }
// after
const n = typeof value === 'string' && /^\d+$/.test(value) ? Number(value) : value;
if (!Number.isSafeInteger(n) || n < 0) { throw ... }
return n;
Defensive patterns

Strategy: type-guard

Validate before calling

const wc = body.wordCount;
if (wc != null && wc !== '' && !(Number.isSafeInteger(wc) && wc >= 0)) {
  console.warn('Unexpected wordCount type from pixiv:', typeof wc, wc);
}

Type guard

const isCount = (v) => v == null || v === '' || (Number.isSafeInteger(v) && v >= 0);

Try / catch

try {
  await novelDownload(id);
} catch (e) {
  if (/returned malformed data/.test(e.message)) {
    console.warn('pixiv payload type changed; inspect raw /ajax/novel response');
  } else throw e;
}

Prevention

When it happens

Trigger: The novel detail JSON has wordCount or bookmarkCount as a string, float, negative number, or other non-integer value (e.g. '' handled earlier, but '123' as a string fails).

Common situations: Pixiv A/B-testing or changing their internal AJAX novel payload types; proxied/cached responses with altered types; scraping through a translation layer that stringifies numbers.

Understand the failure class

Related errors


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