jackwener/OpenCLI · error · CommandExecutionError

Zhihu answer download returned a malformed Browser Bridge pa

Error message

Zhihu answer download returned a malformed Browser Bridge payload

What it means

After the evaluate completes, extractAnswer unwraps the raw result with unwrapEvaluateResult and validates it is a non-null, non-array object before inspecting status/errorCode/value. If the unwrapped payload is not such an object, this error is thrown, meaning the Browser Bridge returned something the downloader could not interpret (null/undefined/array/primitive) rather than the expected {status, errorCode, value,...} envelope.

Source

Thrown at clis/zhihu/download-helpers.js:205

        return { value: {
          answerUrl: typeof payload.url === 'string' ? payload.url : '',
          questionUrl: typeof payload.question?.url === 'string' ? payload.question.url : '',
          title: typeof payload.question?.title === 'string' ? payload.question.title : '',
          author: typeof payload.author?.name === 'string' ? payload.author.name : '',
          createdTime: payload.created_time,
          ...normalized
        } };
      })()
    `).catch((error) => {
        throw new CommandExecutionError(
            `Zhihu answer download request failed: ${error instanceof Error ? error.message : String(error)}`,
            'Try again later or rerun with -v for more detail.',
        );
    });

    const data = unwrapEvaluateResult(raw);
    if (!data || typeof data !== 'object' || Array.isArray(data)) {
        throw new CommandExecutionError('Zhihu answer download returned a malformed Browser Bridge payload');
    }
    const status = data.status;
    if (String(data.errorCode) === '40362') {
        throw new CommandExecutionError(
            `Zhihu risk control blocked answer ${target.answerId} (40362): ${data.errorMessage || 'abnormal request'}`,
            'Open the answer in the connected Chrome profile and retry later.',
        );
    }
    if (status === 401 || status === 403 || String(data.errorCode) === '40353' || data.needLogin) {
        throw new AuthRequiredError('www.zhihu.com', 'Failed to download Zhihu answer');
    }
    if (status === 404) {
        throw new EmptyResultError('zhihu download', `No Zhihu answer was found for ${target.answerId}.`);
    }
    if (status || data.fetchError) {
        throw new CommandExecutionError(
            status ? `Zhihu answer download request failed (HTTP ${status})` : 'Zhihu answer download request failed',
            String(data.fetchError || data.errorMessage || 'Try again later or rerun with -v for more detail.'),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update @jackwener/opencli and the Browser Bridge/driver to matching versions so evaluate results unwrap consistently.
  2. Rerun with -v and log the raw evaluate result to inspect what shape actually came back.
  3. Retry the command — a transient bridge glitch can yield an empty/null result.
  4. If reproducible, check unwrapEvaluateResult/paginate.js for the expected envelope and confirm the connected bridge implements it.

Example fix

// before
const data = await extractAnswer(page, target); // may throw malformed-payload
// after
try {
  const data = await extractAnswer(page, target);
} catch (err) {
  if (/malformed Browser Bridge payload/.test(err.message)) {
    console.error('Bridge returned unusable payload; update opencli + bridge and retry');
    await bridge.restart();
    return extractAnswer(page, target);
  }
  throw err;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// after a successful raw run, assert the bridge envelope shape yourself
function looksLikeBridgeEnvelope(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v);
}
const url = await page.getCurrentUrl();
if (!url || !url.includes('/answer/')) throw new Error('not on an answer page');

Type guard

function isBridgePayload(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v)
    && ('status' in v || 'value' in v || 'errorCode' in v || 'malformed' in v);
}

Try / catch

try {
  const data = await extractAnswer(page, target);
} catch (err) {
  if (String(err.message).includes('malformed Browser Bridge payload')) {
    // protocol/version mismatch or empty evaluate result — upgrade bridge, retry
    await bridge.restart();
    return extractAnswer(page, target);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling extractAnswer when page.evaluate resolves to a value that, after unwrapEvaluateResult, is not a plain object: the bridge returned null/undefined for a failed evaluation, an array, a bare string/number, or an unexpected wrapper shape due to a Browser Bridge protocol/version mismatch.

Common situations: Outdated or mismatched Browser Bridge/driver version serializing evaluate results differently; the evaluate returned undefined because the in-page script silently exited; the bridge's result-unwrapping convention changed between library versions; a corrupted or truncated bridge response.

Understand the failure class

Related errors


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