jackwener/OpenCLI · error · CommandExecutionError

Pixiv pages API returned malformed payload

Error message

Pixiv pages API returned malformed payload

What it means

Thrown when the pixiv /ajax/illust/{id}/pages endpoint returns a JSON body that is not an array. The library expects an array of page objects; anything else means the API contract changed or the response was an error/HTML page that was not caught as a not-found.

Source

Thrown at clis/pixiv/download.js:37

    domain: 'www.pixiv.net',
    strategy: Strategy.COOKIE,
    args: [
        { name: 'illust-id', positional: true, required: true, help: 'Illustration ID' },
        { name: 'output', default: './pixiv-downloads', help: 'Output directory' },
    ],
    columns: ['index', 'type', 'status', 'size'],
    func: async (page, kwargs) => {
        const illustId = String(kwargs['illust-id'] ?? '');
        const output = String(kwargs.output ?? './pixiv-downloads');
        if (!/^\d+$/.test(illustId)) {
            throw new CommandExecutionError(`Invalid illustration ID: ${illustId}`);
        }
        // pixivFetch handles navigate + error checking; returns the response body directly
        const pages = await pixivFetch(page, `/ajax/illust/${illustId}/pages`, {
            notFoundMsg: `Illustration not found: ${illustId}`,
        });
        if (!Array.isArray(pages)) {
            throw new CommandExecutionError('Pixiv pages API returned malformed payload');
        }
        if (pages.length === 0) {
            throw new EmptyResultError('pixiv download', `No images found for illustration ${illustId}.`);
        }
        // Extract cookies for authenticated downloads
        const cookies = formatCookieHeader(await page.getCookies({ domain: 'pixiv.net' }));
        // Create output directory
        const outputDir = path.join(output, illustId);
        fs.mkdirSync(outputDir, { recursive: true });
        const results = [];
        for (let i = 0; i < pages.length; i++) {
            const p = pages[i];
            const url = p.urls?.original || p.urls?.regular || '';
            if (!url) {
                results.push({ index: i + 1, type: 'image', status: 'failed', size: 'No URL' });
                continue;
            }
            try {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry after a delay and reduce request rate to avoid pixiv throttling
  2. Re-authenticate / refresh pixiv cookies so the AJAX endpoint returns real data
  3. Log or inspect the raw response body to confirm what pixiv actually returned
  4. Check whether pixiv changed the /ajax/illust/{id}/pages response format and update the tool
Defensive patterns

Strategy: try-catch

Validate before calling

const body = await fetch(`https://www.pixiv.net/ajax/illust/${id}/pages`);
const ct = body.headers.get('content-type') || '';
if (!ct.includes('json')) throw new Error('Non-JSON response from pixiv');

Type guard

const isPagesArray = (v) => Array.isArray(v) && v.length >= 0;

Try / catch

try {
  await pixivDownload({ illustId });
} catch (e) {
  if (e.message === 'Pixiv pages API returned malformed payload') {
    await sleep(5000); // back off, likely throttled
    // retry once, then inspect raw response
  } else throw e;
}

Prevention

When it happens

Trigger: Pixiv returns an unexpected object or null for the pages endpoint (rate limiting page, login redirect, HTML error page parsed as JSON, or a pixiv API schema change).

Common situations: Aggressive scripted downloading triggers pixiv rate limiting or bot detection; user session is invalid so a redirect payload is returned; pixiv changes their internal AJAX API shape.

Understand the failure class

Related errors


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