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
- Inspect the raw /ajax/novel/{id} response to see the actual type of wordCount/bookmarkCount
- Re-fetch after a short delay in case of a transient bad response
- Update the parsing code to coerce numeric strings with Number() when pixiv changes types
- 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
- Log raw novel payloads when counters look wrong
- Retry transiently before assuming an API change
- Coerce numeric strings defensively in your own pre-fetch checks
- Track pixiv AJAX schema changes
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ${label} returned a malformed payload
- Pixiv novel ${id} returned malformed content payload
- No user message found in request
- Bilibili creator comparison returned malformed stat data for
- Bilibili creator comparison returned malformed metric ${defi
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1de70aeae84b9fff.
Report an issue: GitHub.