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
- Call action=scopes with the frame_id first, then pass a returned scope's variablesReference as scope_id
- Or pass variable_ref from a previous variables response to expand a nested object
- 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
- Follow the DAP flow: scopes(frame_id) → variables(variablesReference)
- Do not call variables with reference 0 — it means 'no children'
- Cache references per paused session; they are invalidated on resume/restart
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
- set_breakpoint requires file+line or function
- remove_breakpoint requires file+line or function
- instruction_reference is required for set_instruction_breakp
- instruction_reference is required for remove_instruction_bre
- name is required for data_breakpoint_info
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a220bf9d3749d9be.
Report an issue: GitHub.