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.

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)

Solutions

  1. Provide the expression to evaluate, e.g. {expression: 'myVar.length', frame_id: 1}
  2. Optionally set context ('repl', 'watch', 'hover', etc.) — it defaults to 'repl'
  3. 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

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 parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e0611c6151934185. Report an issue: GitHub.