jackwener/OpenCLI · error · CommandExecutionError
Pixiv bookmarks returned malformed payload
Error message
Pixiv bookmarks returned malformed payload
What it means
normalizeBookmarkWorks validates the JSON returned by Pixiv's /ajax/user/<id>/.../bookmarks endpoint before rows are built. It accepts a plain array, an object with a `works` array, or an object with an object-valued `works` map; anything else is a payload shape the library cannot safely iterate, so it throws this CommandExecutionError to surface upstream/API drift instead of producing garbage rows.
Source
Thrown at clis/pixiv/bookmark-utils.js:55
throw new CommandExecutionError('Pixiv item returned malformed tag');
}
return value.trim();
}).join(', ');
}
function optionalCount(value, label, fallback = '') {
if (value == null || value === '') return fallback;
if (!Number.isSafeInteger(value) || value < 0) {
throw new CommandExecutionError(`Pixiv bookmark item returned malformed ${label}`);
}
return value;
}
export function normalizeBookmarkWorks(body) {
if (Array.isArray(body)) return body;
if (Array.isArray(body?.works)) return body.works;
if (body?.works && typeof body.works === 'object') return Object.values(body.works);
throw new CommandExecutionError('Pixiv bookmarks returned malformed payload');
}
export function bookmarkRow(work, index, type, bookmarkOwnerId) {
const item = requirePixivPayloadObject(work, 'Pixiv bookmark item');
const isNovel = type === 'novel';
const id = requirePixivId(item.id ?? (isNovel ? item.novelId : item.illustId), 'Pixiv bookmark item');
const title = requirePixivString(item.title ?? item.illustTitle, 'Pixiv bookmark item');
const author = requirePixivString(item.userName ?? item.user_name, 'Pixiv bookmark item');
const userId = requirePixivId(item.userId ?? item.user_id, 'Pixiv bookmark item');
return {
rank: index + 1,
type,
bookmark_owner_id: bookmarkOwnerId,
title,
author,
user_id: userId,
illust_id: isNovel ? '' : id,
novel_id: isNovel ? id : '',View on GitHub (pinned to 49907e53dc)
Solutions
- Check Pixiv login state: re-authenticate the page/session, since an unauthenticated ajax response is the most common cause of a non-works payload.
- Log the raw body before calling normalizeBookmarkWorks (or catch and inspect body) to see the actual schema returned.
- Update the normalizer to handle the new response shape (e.g. accept body.bookmarks or body.body.works) if Pixiv changed its schema.
- Retry after a delay if the payload was a rate-limit/error envelope; use pixivFetch's error handling / notFoundMsg paths.
- Pin/verify the library version matches the current Pixiv API behavior; upgrade if a fix exists.
Example fix
// before
const body = await pixivFetch(page, path, {...});
const works = normalizeBookmarkWorks(body);
// after
const body = await pixivFetch(page, path, {...});
let works;
try {
works = normalizeBookmarkWorks(body);
} catch (e) {
if (!body?.error) throw e;
throw new CommandExecutionError(`Pixiv bookmarks request failed: ${body.message ?? 'unauthenticated or rate-limited'}`);
} Defensive patterns
Strategy: type-guard
Validate before calling
function isUsableBookmarksBody(body) {
return Array.isArray(body) ||
Array.isArray(body?.works) ||
(body?.works && typeof body.works === 'object');
}
if (!isUsableBookmarksBody(body)) {
console.error('Unexpected bookmarks payload:', JSON.stringify(body).slice(0, 500));
} Type guard
function isUsableBookmarksBody(body) {
return Array.isArray(body) ||
(body !== null && typeof body === 'object' &&
(Array.isArray(body.works) || (body.works !== null && typeof body.works === 'object')));
} Try / catch
try {
const works = normalizeBookmarkWorks(body);
// ...build rows
} catch (e) {
if (e.message.includes('malformed payload')) {
// inspect/log raw body, check login state, then rethrow or degrade gracefully
throw new Error(`Bookmarks unavailable (payload shape: ${typeof body}); check Pixiv login/session`, { cause: e });
}
throw e;
} Prevention
- Keep the Pixiv session authenticated; most malformed payloads come from login-page or error responses.
- Log the raw ajax body on failure to detect Pixiv schema changes early.
- Wrap normalizeBookmarkWorks and degrade gracefully (return empty rows + warning) for read-only tooling.
- Add a smoke test that runs fetchCurrentBookmarks and asserts the payload guard passes.
- Pin and periodically update the library against Pixiv API drift.
When it happens
Trigger: Pixiv's ajax endpoint returns an HTML login page, an error JSON like {"error":true,...}, an empty body, or a new schema where bookmarks live under a different key — any body that is neither an array nor an object with a usable `works` field.
Common situations: Expired or missing Pixiv login session so the ajax call returns a redirect/login page; Pixiv A/B-testing a new bookmark response schema; rate-limit or error envelope JSON returned with HTTP 200; scraping a region where the endpoint is gated.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Pixiv illustration ${id} returned malformed detail payload
- LinkedIn people search returned malformed extraction payload
- LinkedIn sent invitations returned a malformed extraction pa
- LinkedIn services-read returned malformed extraction payload
- Manus credits returned a malformed API payload
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/04e4680d1f9b2999.
Report an issue: GitHub.