can1357/oh-my-pi · error · ToolError

variables requires variable_ref or scope_id

Error message

variables requires variable_ref or scope_id

What it means

The variables action throws this ToolError when neither variable_ref nor scope_id is provided. Listing variables requires a variablesReference handle obtained from a scopes or variables response; the tool derives the handle as variable_ref ?? scope_id and errors if both are undefined.

Source

Thrown at packages/coding-agent/src/tools/debug.ts:991

				details.stackFrames = response.stackFrames;
				return result.text(formatStackFrames(response.stackFrames)).done();
			}
			case "threads": {
				const response = await dapSessionManager.threads(combinedSignal, timeoutSec * 1000);
				details.snapshot = response.snapshot;
				details.threads = response.threads;
				return result.text(formatThreads(response.threads)).done();
			}
			case "scopes": {
				const response = await dapSessionManager.scopes(params.frame_id, combinedSignal, timeoutSec * 1000);
				details.snapshot = response.snapshot;
				details.scopes = response.scopes;
				return result.text(formatScopes(response.scopes)).done();
			}
			case "variables": {
				const variableReference = params.variable_ref ?? params.scope_id;
				if (variableReference === undefined) {
					throw new ToolError("variables requires variable_ref or scope_id");
				}
				const response = await dapSessionManager.variables(variableReference, combinedSignal, timeoutSec * 1000);
				details.snapshot = response.snapshot;
				details.variables = response.variables;
				return result.text(formatVariables(response.variables)).done();
			}
			case "disassemble": {
				requireCapability("supportsDisassembleRequest", "disassembly");
				if (params.instruction_count === undefined) {
					throw new ToolError("instruction_count is required for disassemble");
				}
				const response = await dapSessionManager.disassemble(
					resolveDisassemblyReference(params.memory_reference),
					params.instruction_count,
					params.offset,
					params.instruction_offset,
					params.resolve_symbols,
					combinedSignal,

View on GitHub (pinned to 9690622007)

Solutions

  1. Call action=scopes with the frame_id first, then pass a returned scope's variablesReference as scope_id
  2. Or pass variable_ref from a previous variables response to expand a nested object
  3. Note: a reference of 0 usually means 'no children' in DAP — do not call variables with it; check the response instead

Example fix

// before
await debugTool.run({ action: 'variables', frame_id: 1 }); // frame_id is not a variable reference
// after
const scopes = await debugTool.run({ action: 'scopes', frame_id: 1 });
await debugTool.run({ action: 'variables', scope_id: scopes.scopes[0].variablesReference });
Defensive patterns

Strategy: type-guard

Validate before calling

function canListVariables(params) {
  const ref = params.variable_ref ?? params.scope_id;
  return typeof ref === 'number' && ref > 0;
}
if (!canListVariables(params)) throw new Error('variables needs a positive variable_ref or scope_id');

Type guard

function hasVariableReference(p) {
  const ref = (p as { variable_ref?: unknown; scope_id?: unknown });
  return typeof p === 'object' && p !== null
    && (typeof ref.variable_ref === 'number' && ref.variable_ref > 0
      || typeof ref.scope_id === 'number' && ref.scope_id > 0);
}

Try / catch

try {
  await debugTool.run({ action: 'variables', ...params });
} catch (err) {
  if (err instanceof ToolError && err.message.includes('requires variable_ref or scope_id')) {
    // call scopes with frame_id first, then retry with a returned variablesReference
  } else throw err;
}

Prevention

When it happens

Trigger: Calling action=variables with neither params.variable_ref nor params.scope_id set, or both explicitly undefined.

Common situations: Caller forgets the two-step flow (scopes → variables) and tries to list variables for a frame directly; variable_ref 0 treated as falsy by caller-side code that strips zero/optional fields; stale reference after session restart.

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/a220bf9d3749d9be. Report an issue: GitHub.