jackwener/OpenCLI · error · CommandExecutionError
Pixiv novel returned malformed series ID
Error message
Pixiv novel returned malformed series ID
What it means
novelRowFromBody requires that any non-empty series ID is a string of digits. If seriesId (from b.seriesId or seriesNavData.seriesId) is missing, empty, or contains non-numeric characters, the response's series identity is unusable for the novel_id/series_id columns and linking, so it throws CommandExecutionError.
Source
Thrown at clis/pixiv/novel.js:39
const userId = String(body.userId ?? '').trim();
if (!/^\d+$/.test(novelId) || novelId !== id || !title || !userName || !/^\d+$/.test(userId)) {
throw new CommandExecutionError(`Pixiv novel ${id} returned malformed detail payload`);
}
return { payload: body, identity: { novelId, title, userName, userId } };
}
export function novelRowFromBody(body, id) {
const normalized = requireNovelBody(body, id);
const b = normalized.payload;
const identity = normalized.identity;
if (b.seriesNavData != null && (Array.isArray(b.seriesNavData) || typeof b.seriesNavData !== 'object')) {
throw new CommandExecutionError('Pixiv novel returned malformed series metadata');
}
const series = b.seriesNavData || {};
const seriesId = b.seriesId ?? series.seriesId ?? '';
const seriesTitle = b.seriesTitle ?? series.title ?? '';
if (seriesId !== '' && !/^\d+$/.test(String(seriesId))) {
throw new CommandExecutionError('Pixiv novel returned malformed series ID');
}
if (seriesTitle !== '' && typeof seriesTitle !== 'string') {
throw new CommandExecutionError('Pixiv novel returned malformed series title');
}
const seriesOrder = series.order ?? b.seriesContentOrder ?? '';
if (seriesOrder !== '' && (!Number.isSafeInteger(seriesOrder) || seriesOrder < 1)) {
throw new CommandExecutionError('Pixiv novel returned malformed series order');
}
return {
novel_id: identity.novelId,
title: identity.title,
author: identity.userName,
user_id: identity.userId,
series_id: seriesId === '' ? '' : String(seriesId),
series_title: seriesTitle || '',
series_order: seriesOrder,
words: optionalCount(b.wordCount, 'word count'),
characters: optionalCount(b.characterCount ?? b.textCount, 'character count'),View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw response and confirm the actual seriesId value for that novel
- Retry with an authenticated/logged-in Pixiv session — partial series data often comes from restricted content
- Update the CLI parser to handle the new ID format if Pixiv changed the schema
- Sanitize/normalize the field (strip whitespace, take the numeric part) before calling novelRowFromBody
Example fix
// before const seriesId = body.seriesNavData.seriesId; // " 105889 " // after const seriesId = String(body.seriesNavData.seriesId ?? '').trim();
Defensive patterns
Strategy: validation
Validate before calling
const sid = body?.seriesNavData?.seriesId;
if (sid !== undefined && sid !== '' && !/^\d+$/.test(String(sid))) {
throw new Error(`bad seriesId: ${sid}`);
} Type guard
function isDigitString(v) {
return typeof v === 'string' && /^\d+$/.test(v);
} Try / catch
try {
const row = novelRowFromBody(body, id);
} catch (e) {
if (e.message.includes('malformed series ID')) {
body.seriesId = String(body.seriesNavData?.seriesId ?? '').replace(/\D/g, '');
} else throw e;
} Prevention
- Trim and normalize IDs before validation
- Keep fixtures in sync with the live API schema
- Retry restricted content with an authenticated session to avoid partial series data
When it happens
Trigger: Pixiv returns seriesNavData.seriesId (or top-level seriesId) as a non-numeric string, null coerced oddly, an object, or a numeric-looking value with whitespace/sign/decimal characters; only triggers when seriesId !== ''.
Common situations: API returns localized/obfuscated IDs during an A/B rollout; a proxy rewrites fields; a fixture uses 'abc' or '12345.6' for seriesId; scraping an region-locked novel returns partial series data.
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
- Pixiv novel returned malformed series metadata
- Bilibili ${label} API returned malformed top_replies
- Bilibili creator comparison returned malformed stat data for
- Bilibili view API returned malformed paid-content metadata
- Nowcoder returned a malformed ${label}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/69489eb3d3bc2f2e.
Report an issue: GitHub.