jackwener/OpenCLI · error · Error
evaluateWithArgs: invalid key "${key}"
Error message
evaluateWithArgs: invalid key "${key}" What it means
evaluateWithArgs (src/browser/base-page.ts:189) interpolates each key of the args record as a const declaration (`const ${key} = ${JSON.stringify(value)};`) prepended to the evaluated script. To keep the generated code valid, keys must be valid JavaScript identifiers, enforced by the regex ^[a-zA-Z_$][a-zA-Z0-9_$]*$. Any key that isn't (spaces, dashes, leading digits, empty string) throws immediately.
Source
Thrown at src/browser/base-page.ts:189
/**
* Safely evaluate JS with pre-serialized arguments.
* Each key in `args` becomes a `const` declaration with JSON-serialized value,
* wrapped in a lexical block to avoid polluting the global execution context.
*
* Why a block: Chrome's Runtime.evaluate shares a single global context per page.
* Top-level `const` declarations persist across calls, so re-declaring the same
* variable name (e.g. `markerAttr` in both click resolution and file upload)
* throws "SyntaxError: Identifier has already been declared". A block keeps
* the args scoped without forcing callers to pass expression-only code.
*
* Usage:
* page.evaluateWithArgs(`(async () => { return sym; })()`, { sym: userInput })
*/
async evaluateWithArgs(js: string, args: Record<string, unknown>): Promise<unknown> {
const declarations = Object.entries(args)
.map(([key, value]) => {
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) {
throw new Error(`evaluateWithArgs: invalid key "${key}"`);
}
return `const ${key} = ${JSON.stringify(value)};`;
})
.join('\n');
return this.evaluate(`{\n${declarations}\n${js}\n}`);
}
async fetchJson(url: string, opts: FetchJsonOptions = {}): Promise<unknown> {
const request = {
url,
method: opts.method ?? 'GET',
headers: opts.headers ?? {},
body: opts.body,
hasBody: opts.body !== undefined,
timeoutMs: opts.timeoutMs ?? 15_000,
};
const result = await this.evaluateWithArgs(`View on GitHub (pinned to 49907e53dc)
Solutions
- Rename keys to valid JS identifiers before calling (camelCase them, or use a fixed safe set of argument names).
- Pass the problematic values as a single object under one valid key, e.g. { data: { "data-foo": 1 } }, and destructure inside the script.
- Sanitize/validate input keys with the same identifier regex at your API boundary.
- If the key is dynamic and unavoidable, serialize args into the script via JSON.parse of a string argument instead of identifier declarations.
Example fix
// before
await page.evaluateWithArgs(js, { 'data-id': id });
// after
await page.evaluateWithArgs(js, { dataId: id });
// or
await page.evaluateWithArgs(js, { payload: { 'data-id': id } }); Defensive patterns
Strategy: validation
Validate before calling
const isIdent = (k: string) => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k);
const bad = Object.keys(args).filter(k => !isIdent(k));
if (bad.length) throw new Error(`sanitize arg keys before evaluateWithArgs: ${bad.join(', ')}`); Type guard
function hasIdentifierKeys(args: Record<string, unknown>): args is Record<`string` extends never ? never : string, unknown> & { __valid: true } {
return Object.keys(args).every(k => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k));
} Prevention
- Always use fixed, camelCase argument names you control (e.g. { payload, el, text }).
- Bundle arbitrary-keyed data under one valid key and destructure inside the script.
- Validate user/config-supplied keys with the identifier regex at your API boundary.
- Never pass HTML attribute names, query params, or labels directly as arg keys.
When it happens
Trigger: Passing an args object with keys like {"data-foo": 1}, {"my key": 2}, {"1st": x}, {"": v}, or keys containing dots/slashes — typically when keys come from user input, config files, or are derived from element names/labels.
Common situations: Mapping HTML attribute names (href, data-id) directly as arg keys; building args from query params or JSON with non-identifier keys; forwarding an arbitrary record without sanitizing key names.
Related errors
- INVALID_ARGUMENT
- INVALID_ARGUMENT
- ${label} is required
- ${label} returned an unexpected payload shape; expected an o
- ${label} returned an unexpected payload shape; expected an a
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/dc1e66ef7a791edd.
Report an issue: GitHub.