can1357/oh-my-pi · error · ToolError
${label} threw a JavaScript exception:\n${value.__ompErr}
Error message
${label} threw a JavaScript exception:\n${value.__ompErr} What it means
`unwrapEvalEnvelope` inspects values returned by cmux eval RPCs. The in-page wrapper serializes a thrown exception as `{ __ompErr: "<stack/message>" }`; when seen, this function rethrows it as a ToolError `<label> threw a JavaScript exception:` followed by the original error text. It converts silent in-page JS failures into actionable host-side errors for `evaluate`/`evaluateOnSelector`.
Source
Thrown at packages/coding-agent/src/tools/browser/cmux/rpc.ts:160
const __v = (${expr});
if (__v && typeof __v.then === "function") return { __ompPromise: true };
return { __ompOk: __v === undefined ? null : __v };
} catch (e) {
return { __ompErr: (e && (e.stack || e.message)) || String(e) };
}
})()`;
}
/**
* Decode a {@link serializeEvalWithEnvelope} result: rethrow page-side
* exceptions as rich {@link ToolError}s, reject unserializable Promise
* returns with an actionable message, and pass through values from daemons
* that did not run the wrapper.
*/
export function unwrapEvalEnvelope<TResult>(value: unknown, label: string): TResult {
if (value && typeof value === "object") {
if ("__ompErr" in value && typeof value.__ompErr === "string") {
throw new ToolError(`${label} threw a JavaScript exception:\n${value.__ompErr}`);
}
if ("__ompPromise" in value && value.__ompPromise === true) {
throw new ToolError(
`${label} returned a Promise, but this surface evaluates synchronously and cannot await it — return a plain value (poll with waitForFunction for async state instead)`,
);
}
if ("__ompOk" in value) {
return value.__ompOk as TResult;
}
}
return value as TResult;
}
export function mapWaitUntil(waitUntil: string | undefined): "interactive" | "complete" {
return waitUntil === "domcontentloaded" ? "interactive" : "complete";
}
export interface ResolveCmuxKindOptions {View on GitHub (pinned to 9690622007)
Solutions
- Read the embedded __ompErr text — it names the exact line/exception in your script; fix the script accordingly.
- Null-check DOM results inside the script: `const el = document.querySelector(sel); if (!el) return null;`.
- Validate the script's syntax (it's a string — an editor/lint pass catches typos) and prefer evaluateOnSelector for element work instead of manual querySelector.
Example fix
// before
tab.evaluate(`document.querySelector('.price').textContent`);
// after
tab.evaluate(`(() => { const el = document.querySelector('.price'); return el ? el.textContent : null; })()`); Defensive patterns
Strategy: try-catch
Validate before calling
// validate script syntax before sending new Function(script); // throws SyntaxError locally if the script string is malformed
Try / catch
try {
const price = await tab.evaluate(script);
} catch (err) {
if (err instanceof ToolError && err.message.includes('threw a JavaScript exception')) {
console.error('in-page script failed:', err.message.split('\n').slice(1).join('\n'));
// fall back to a null-safe variant of the script
}
throw err;
} Prevention
- Write eval scripts as IIFEs with null checks on querySelector results.
- Lint the script string (it's plain text — syntax errors only surface in-page).
- Prefer evaluateOnSelector / built-in selector actions over hand-written querySelector code.
- Return null or a sentinel for missing elements instead of dereferencing blindly.
When it happens
Trigger: The script passed to tab.evaluate/evaluateOnSelector throws in the page: TypeError on null querySelector results, syntax errors, reference errors, or calling page-only APIs incorrectly.
Common situations: Selector matched nothing and the script dereferences the result; using browser APIs unavailable in the page context; JSON-injected script literals with quoting issues breaking syntax; page CSP or hydration timing.
Related errors
- agent() received invalid arguments: ${result.summary}
- agent() blocked: turn token budget exhausted (${turnBudget.s
- ${failureMessage}${recoveryHint} (subagent failure: ${policy
- agent() isolated apply failed for ${result.id}${summary ? `:
- agent() isolated nested patch apply failed for ${result.id}:
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5b29316fcaa22806.
Report an issue: GitHub.