can1357/oh-my-pi · error · ToolError
expression is required for evaluate
Error message
expression is required for evaluate
What it means
The evaluate action throws this ToolError when params.expression is missing. Evaluating an expression in the paused debuggee requires the expression string; there is no implicit default. Unlike breakpoint actions there is no capability gate — the check runs unconditionally.
Solutions
- Provide the expression to evaluate, e.g. {expression: 'myVar.length', frame_id: 1}
- Optionally set context ('repl', 'watch', 'hover', etc.) — it defaults to 'repl'
- Guard empty interpolated expressions on the caller side before invoking the tool
Example fix
// before
await debugTool.run({ action: 'evaluate', expression: userInput }); // userInput was ''
// after
if (userInput.trim()) await debugTool.run({ action: 'evaluate', expression: userInput, frame_id: 1 }); Defensive patterns
Strategy: validation
Validate before calling
if (typeof params.expression !== 'string' || params.expression.trim().length === 0) {
throw new Error('evaluate needs a non-empty expression');
} Type guard
function hasExpression(p) {
return typeof p === 'object' && p !== null
&& typeof (p as { expression?: unknown }).expression === 'string'
&& (p as { expression: string }).expression.trim().length > 0;
} Try / catch
try {
await debugTool.run({ action: 'evaluate', ...params });
} catch (err) {
if (err instanceof ToolError && err.message.includes('expression is required')) {
// skip or prompt for a real expression instead of evaluating an empty one
} else throw err;
} Prevention
- Interpolation of user/template input: check the result is non-empty before calling
- Name the field exactly 'expression' per the tool schema
- Provide frame_id from the paused state for correct scope resolution
When it happens
Trigger: Calling action=evaluate with params.expression undefined, empty string, or whitespace-only (falsy).
Common situations: Agent sends an empty evaluate to 'refresh' watches; expression field named wrong (e.g. expr/code); template interpolation produced an empty string at runtime.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- data_id is required for remove_data_breakpoint
- data_id is required for set_data_breakpoint
- instruction_count is required for disassemble
- instruction_reference is required for…
- instruction_reference is required for…
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e0611c6151934185.
Report an issue: GitHub.
Appendix: source
Thrown at packages/coding-agent/src/tools/debug.ts:956
details.state = outcome.state;
details.timedOut = outcome.timedOut;
return result.text(buildOutcomeText(outcome, timeoutSec, "Step in")).done();
}
case "step_out": {
const outcome = await dapSessionManager.stepOut(combinedSignal, timeoutSec * 1000);
details.snapshot = outcome.snapshot;
details.state = outcome.state;
details.timedOut = outcome.timedOut;
return result.text(buildOutcomeText(outcome, timeoutSec, "Step out")).done();
}
case "pause": {
const snapshot = await dapSessionManager.pause(combinedSignal, timeoutSec * 1000);
details.snapshot = snapshot;
return result.text(formatSessionSnapshot(snapshot).concat("Program paused.").join("\n")).done();
}
case "evaluate": {
if (!params.expression) {
throw new ToolError("expression is required for evaluate");
}
const evaluationContext = (params.context as DapEvaluateArguments["context"] | undefined) ?? "repl";
const response = await dapSessionManager.evaluate(
params.expression,
evaluationContext,
params.frame_id,
combinedSignal,
timeoutSec * 1000,
);
details.snapshot = response.snapshot;
details.evaluation = response.evaluation;
return result.text(formatEvaluation(response.evaluation)).done();
}
case "stack_trace": {
const response = await dapSessionManager.stackTrace(params.levels, combinedSignal, timeoutSec * 1000);
details.snapshot = response.snapshot;
details.stackFrames = response.stackFrames;
return result.text(formatStackFrames(response.stackFrames)).done();View on GitHub (pinned to 9690622007)