ruvnet/ruflo · error
browser/eval: script exceeds maximum length of
Error message
browser/eval: script exceeds maximum length of ${MAX_EVAL_SCRIPT_LENGTH} characters What it means
Thrown by the browser/eval MCP tool handler when the submitted script exceeds MAX_EVAL_SCRIPT_LENGTH characters. The limit defaults to 20,000 and can be overridden via the CLAUDE_FLOW_MAX_EVAL_SCRIPT_LENGTH environment variable (parsed at module load). The JSON schema also declares maxLength, but this handler-level check is what enforces it deterministically.
Solutions
- Split the work into multiple smaller browser/eval calls that each stay under the limit
- Move large data out of the script: fetch/derive the data inside the page or via other tools instead of inlining it
- Raise the limit deliberately via CLAUDE_FLOW_MAX_EVAL_SCRIPT_LENGTH=<n> on the server process if the workload genuinely needs longer scripts (note: it is read once at startup)
Example fix
// before
await tools.invoke('browser/eval', { script: hugeMinifiedBundle }); // > 20000 chars
// after
for (const chunk of splitScript(hugeMinifiedBundle, 19000)) {
await tools.invoke('browser/eval', { script: chunk });
}
// or raise the cap for the server process:
// CLAUDE_FLOW_MAX_EVAL_SCRIPT_LENGTH=50000 node server.js Defensive patterns
Strategy: validation
Validate before calling
const MAX = Number(process.env.CLAUDE_FLOW_MAX_EVAL_SCRIPT_LENGTH) || 20000;
if (script.length > MAX) {
const chunks = splitScript(script, MAX - 1000);
for (const c of chunks) await tools.invoke('browser/eval', { script: c });
} else {
await tools.invoke('browser/eval', { script });
} Try / catch
try { await tools.invoke('browser/eval', { script }); } catch (e) { if (e instanceof Error && e.message.includes('exceeds maximum length')) { await runInChunks(script); } else throw e; } Prevention
- Keep large data out of eval scripts; pass selectors/ids instead of payloads
- Remember CLAUDE_FLOW_MAX_EVAL_SCRIPT_LENGTH is read once at server startup — restart after changing it
When it happens
Trigger: Submitting a script longer than 20,000 chars with the default limit; setting CLAUDE_FLOW_MAX_EVAL_SCRIPT_LENGTH lower (e.g. 1000) and then sending previously-accepted scripts; inlining large data blobs or base64 payloads into the script body.
Common situations: Generated scripts that embed scraped page data inline; minified bundles pasted as eval scripts; teams tightening the env limit for security after scripts were already written against the default.
Related errors
- browser/eval: script contains disallowed pattern
- browser/eval: script must not be empty
- allowedMcpTools entries must be non-empty strings
- allowedMcpTools must have ≥1 entry
- Failed to load WASM module
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/01f381a7bfcea857.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/browser/src/mcp-tools/browser-tools.ts:671
properties: {
session: { type: 'string', description: 'Session ID' },
script: {
type: 'string',
description: `JavaScript code to execute (max ${MAX_EVAL_SCRIPT_LENGTH} chars)`,
maxLength: MAX_EVAL_SCRIPT_LENGTH,
},
},
required: ['script'],
},
handler: async (input) => {
const script = input.script as string;
// Validate script length
if (!script || script.length === 0) {
throw new Error('browser/eval: script must not be empty');
}
if (script.length > MAX_EVAL_SCRIPT_LENGTH) {
throw new Error(`browser/eval: script exceeds maximum length of ${MAX_EVAL_SCRIPT_LENGTH} characters`);
}
// Check for dangerous patterns
for (const pattern of DANGEROUS_EVAL_PATTERNS) {
if (pattern.test(script)) {
throw new Error(`browser/eval: script contains disallowed pattern: ${pattern.source}`);
}
}
// Audit log
console.info(`[browser/eval] Executing script (${script.length} chars) in session ${input.session || 'default'}`);
const adapter = getAdapter(input.session as string);
return adapter.eval({ script });
},
},
];
View on GitHub (pinned to fa13ee4ad6)