jackwener/OpenCLI · error · CommandExecutionError

Zhihu ${label} returned a malformed payload

Error message

Zhihu ${label} returned a malformed payload

What it means

Thrown when the evaluated result is not a usable object: either null/undefined, a non-object, or an Array. fetchCommentPage expects Zhihu's comment API shape ({data, paging, ...}), so anything else is rejected as a malformed payload. This catches cases where the in-page fetch succeeded but the unwrapped result lost its structure.

Source

Thrown at clis/zhihu/answer-comments-helpers.js:63

        const result = {
            __httpStatus: response.status,
            __errorCode: error?.code ?? body?.error_code ?? '',
            __errorMessage: error?.message || body?.error_msg || '',
            __needLogin: error?.need_login === true || body?.need_login === true,
        };
        return !response.ok || result.__errorCode || result.__errorMessage || result.__needLogin ? result : body;
    }, url).catch((error) => {
        throw new CommandExecutionError(
            `Zhihu ${label} request failed: ${error instanceof Error ? error.message : String(error)}`,
            'Try again later or rerun with -v for more detail.',
        );
    });
    const payload = unwrapEvaluateResult(evaluated);
    if (payload?.__malformedJson) {
        throw new CommandExecutionError(`Zhihu ${label} returned malformed JSON: ${payload.__malformedJson}`);
    }
    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
        throw new CommandExecutionError(`Zhihu ${label} returned a malformed payload`);
    }
    const status = payload.__httpStatus;
    const code = String(payload.__errorCode || '');
    if (status >= 400 || code || payload.__errorMessage || payload.__needLogin) {
        if (code === '40362') {
            throw new CommandExecutionError(
                `Zhihu risk control blocked ${label} (40362): ${payload.__errorMessage || 'abnormal request'}`,
                'Open the answer in the connected Chrome profile and retry later.',
            );
        }
        if (status === 401 || status === 403 || code === '40353' || payload.__needLogin) {
            throw new AuthRequiredError('www.zhihu.com', `Failed to fetch Zhihu ${label}`);
        }
        if (status === 404 && notFoundDetail) throw new EmptyResultError('zhihu answer-comments', notFoundDetail);
        if (status >= 400) throw new CommandExecutionError(`Zhihu ${label} request failed (HTTP ${status})`);
        throw new CommandExecutionError(`Zhihu ${label} returned an error payload: ${payload.__errorMessage || code}`);
    }
    if (!Array.isArray(payload.data) || !payload.paging || typeof payload.paging !== 'object') {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the raw evaluated value with -v to see what shape came back
  2. If the API changed shape (top-level array), update the parsing code to normalize it before this check
  3. Reconnect/refresh the Chrome profile so evaluate returns values correctly
  4. Retry — a transient empty response can pass on a second attempt

Example fix

// before
// fetchCommentPage rejects arrays outright
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) throw ...
// after
// normalize a top-level array into the expected shape before validation
let payload = unwrapEvaluateResult(evaluated);
if (Array.isArray(payload)) payload = { data: payload, paging: {} };
Defensive patterns

Strategy: type-guard

Validate before calling

if (evaluated == null || typeof evaluated !== 'object') { /* abort before validation */ }

Type guard

function isPayloadObject(p){ return p !== null && typeof p === 'object' && !Array.isArray(p); }

Try / catch

try { await fetchCommentPage(url); } catch (e) { if (String(e.message).includes('malformed payload')) { /* re-evaluate with verbose logging or normalize input */ } else throw e; }

Prevention

When it happens

Trigger: unwrapEvaluateResult returned null/undefined, a primitive, or an array — e.g. the evaluate returned nothing, serialization dropped the value, or the endpoint returned a JSON array / bare string rather than an object.

Common situations: Older Zhihu API versions returning a JSON array at the top level; evaluate serialization failures in the Chrome bridge; endpoints that redirect to non-API content.

Understand the failure class

Related errors


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