jackwener/OpenCLI · error · CommandExecutionError
${errorPrefix ? `${errorPrefix}: ` : ''}Boss API returned ma
Error message
${errorPrefix ? `${errorPrefix}: ` : ''}Boss API returned malformed response What it means
assertOk first checks that the response is a non-null object; if not, it throws CommandExecutionError 'Boss API returned malformed response' (optionally prefixed). This happens when the wapi endpoint returns nothing parseable into an object — e.g. an HTML error/anti-bot page that still parsed oddly, or a null/undefined result from page.evaluate after the XHR resolved with non-JSON that later got coerced. It is a defensive shape check before reading data.code.
Source
Thrown at clis/boss/utils.js:88
* Recruiter-only commands (recommend, joblist, stats, resume, mark,
* exchange, invite, greet, batchgreet) have no geek-side equivalent;
* surfacing this as a generic COMMAND_EXEC hides what the user must do.
* chatlist / chatmsg avoid this path by using `allowNonZero: true` and
* branching to the geek-side fetch when they see code 24.
*/
function checkRecruiterSide(data) {
if (data.code === IDENTITY_MISMATCH_CODE) {
throw new AuthRequiredError(BOSS_DOMAIN, RECRUITER_ONLY_MSG);
}
}
/**
* Throw if the API response is not code 0.
* Checks for cookie expiry first, then identity mismatch, then throws
* with the provided message.
*/
export function assertOk(data, errorPrefix) {
if (!data || typeof data !== 'object') {
throw new CommandExecutionError(`${errorPrefix ? `${errorPrefix}: ` : ''}Boss API returned malformed response`);
}
if (data.code === 0)
return;
checkEnvironment(data);
checkAuth(data);
checkRecruiterSide(data);
const prefix = errorPrefix ? `${errorPrefix}: ` : '';
throw new CommandExecutionError(`${prefix}${data.message || 'Unknown error'} (code=${data.code})`);
}
/**
* Make a credentialed XHR request via page.evaluate().
*
* This is the single XHR template — no more copy-pasting the same 15-line
* XMLHttpRequest boilerplate across every adapter.
*
* @returns Parsed JSON response
* @throws On network error, timeout, JSON parse failure, or cookie expiry
*/View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw response (set OPENCLI_VERBOSE or capture xhr.responseText) to see what BOSS actually returned.
- Re-login in the automation Chrome to clear any interstitial/captcha page, then retry.
- Retry after a delay — transient gateway/CDN errors often resolve.
- Check for VPN/proxy interference that could inject HTML error pages.
- Use fetchFriendList-style callers with allowNonZero:false removed only if you intend to handle raw shapes yourself; otherwise upgrade the library version with improved parse handling.
Example fix
// before
const data = await bossFetch(page, url); // data may be null
const list = data.zpData.friendList;
// after
const data = await bossFetch(page, url);
if (!data || typeof data !== 'object') throw new Error('unexpected non-object BOSS response');
const list = data.zpData?.friendList ?? []; Defensive patterns
Strategy: type-guard
Validate before calling
function looksLikeBossEnvelope(v) {
return !!v && typeof v === 'object' && typeof v.code === 'number';
} Type guard
function isBossResponse(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v) && 'code' in v;
} Try / catch
try {
const data = await bossFetch(page, url);
if (!isBossResponse(data)) throw new Error('non-object BOSS payload; session or CDN issue');
} catch (e) {
if (/malformed response/.test(e.message)) {
await reloginIfInterstitial(page); // clear captcha/login HTML pages
return bossFetch(page, url);
}
throw e;
} Prevention
- Re-login when HTML interstitials start replacing JSON payloads
- Retry transiently; empty/gateway responses are often momentary
- Check VPN/proxy for injected HTML error pages
- Run with OPENCLI_VERBOSE to capture raw response bodies for diagnosis
When it happens
Trigger: bossFetch passes data to assertOk but data is null/undefined/non-object — e.g. BOSS returned an empty body, a redirect HTML page string, or page.evaluate serializing a non-object response; assertOk is also called directly by captureJobList on such payloads.
Common situations: BOSS serving an anti-bot or login HTML page instead of JSON; gateway timeouts returning empty bodies; a mobile-captcha interstitial; the session being rejected at CDN level so the 'JSON' is actually markup.
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
- Boss API returned malformed response
- Boss friend list response did not include zpData.friendList
- Chess.com API returned malformed JSON for ${url}: ${error?.m
- coingecko categories returned malformed JSON: ${err?.message
- ${label} returned malformed JSON: ${err?.message ?? err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/56b1e7680a938b2e.
Report an issue: GitHub.