jackwener/OpenCLI · error · CommandExecutionError
Mercury returned malformed ${label}: ${field} must be boolea
Error message
Mercury returned malformed ${label}: ${field} must be boolean What it means
assertBooleanFields walks a list of expected fields on a Mercury state object and requires each to be strictly boolean. Any field that is undefined, null, a string ('true'), or a number throws CommandExecutionError 'Mercury returned malformed <label>: <field> must be boolean'. It protects flag-style fields (e.g. logged-in/loading indicators) from ambiguous truthy values.
Source
Thrown at clis/mercury/utils.js:125
export function assertObject(value, label) {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new CommandExecutionError(`Mercury returned malformed ${label}`);
}
return value;
}
export function assertMercuryState(value, label = 'page state') {
const state = assertObject(value, label);
if (typeof state.url !== 'string' || typeof state.title !== 'string') {
throw new CommandExecutionError(`Mercury returned malformed ${label}`);
}
return state;
}
function assertBooleanFields(state, label, fields) {
for (const field of fields) {
if (typeof state[field] !== 'boolean') {
throw new CommandExecutionError(`Mercury returned malformed ${label}: ${field} must be boolean`);
}
}
return state;
}
export async function inspectMercury(page) {
await page.goto(MERCURY_EXPENSES_URL, { waitUntil: 'load', settleMs: 1500 });
await page.wait({ time: 1 });
const state = await page.evaluate(`(() => {
const text = document.body?.innerText || '';
const url = location.href;
return {
url,
loggedIn: !/\\/login\\b/.test(url) && !/sign in|log in|password|passkey/i.test(text),
hasSubmitExpense: /Submit expense/i.test(text),
hasReimbursements: /Reimbursements|My Expenses|Submitted Expenses/i.test(text),
title: document.titleView on GitHub (pinned to 49907e53dc)
Solutions
- Identify the offending field from the error message and log the raw Mercury payload to confirm its type.
- Update or downgrade the Mercury extension/CLI so both sides agree the field is a real boolean.
- If values arrive as strings, coerce explicitly before validation: state[f] = state[f] === 'true'.
- Ensure any proxy/middleware between Mercury and the CLI preserves JSON boolean types (no template-string rebuilding).
Example fix
// before
const state = JSON.parse(await redis.get('mercury-state')); // booleans stringified by writer
// after
const state = JSON.parse(await redis.get('mercury-state'));
for (const f of ['loggedIn', 'ready']) if (typeof state[f] === 'string') state[f] = state[f] === 'true';
assertBooleanFields(state, 'page state', ['loggedIn', 'ready']); Defensive patterns
Strategy: type-guard
Validate before calling
function hasBooleanFields(v, fields) {
return v !== null && typeof v === 'object' && fields.every(f => typeof v[f] === 'boolean');
} Type guard
function isMercuryStateWithFlags(v, fields) {
return typeof v === 'object' && v !== null && !Array.isArray(v)
&& fields.every(f => typeof v[f] === 'boolean');
} Try / catch
try {
const state = await inspectMercury(page);
} catch (e) {
if (e instanceof CommandExecutionError && e.message.includes('must be boolean')) {
const field = /: (\w+) must be boolean/.exec(e.message)?.[1];
console.error(`Mercury flag field '${field}' has wrong type; check extension/CLI version match`);
} else throw e;
} Prevention
- Don't rebuild Mercury JSON through string templating (coerces types)
- Keep serializers type-preserving (no 'true' strings)
- Pin matching Mercury extension and CLI versions
- Sanity-check boolean flags after any intermediate storage (queues, caches)
When it happens
Trigger: Mercury state missing one of the required boolean fields; field serialized as string 'true'/'false' by an older/newer Mercury version; field present but null; payload passed through a transformation that coerced booleans to 0/1.
Common situations: Version drift between Mercury extension and CLI changing field types; JSON produced by a custom proxy/serializer that stringifies booleans; partially-failed page snapshots omitting fields; middleware logging layers rebuilding state objects.
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
- Mercury returned malformed ${label}
- Bilibili creator comparison returned malformed metric ${defi
- Bilibili creator comparison returned malformed stat data for
- Bilibili creator comparison returned non-integer metric ${de
- Bilibili view API returned a malformed payload during paid-c
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2148e12ac8d6af6e.
Report an issue: GitHub.