{"record":{"id":"a220bf9d3749d9be","repo":"can1357/oh-my-pi","slug":"variables-requires-variable-ref-or-scope-id","errorCode":null,"errorMessage":"variables requires variable_ref or scope_id","messagePattern":"variables requires variable_ref or scope_id","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/debug.ts","lineNumber":991,"sourceCode":"\t\t\t\tdetails.stackFrames = response.stackFrames;\n\t\t\t\treturn result.text(formatStackFrames(response.stackFrames)).done();\n\t\t\t}\n\t\t\tcase \"threads\": {\n\t\t\t\tconst response = await dapSessionManager.threads(combinedSignal, timeoutSec * 1000);\n\t\t\t\tdetails.snapshot = response.snapshot;\n\t\t\t\tdetails.threads = response.threads;\n\t\t\t\treturn result.text(formatThreads(response.threads)).done();\n\t\t\t}\n\t\t\tcase \"scopes\": {\n\t\t\t\tconst response = await dapSessionManager.scopes(params.frame_id, combinedSignal, timeoutSec * 1000);\n\t\t\t\tdetails.snapshot = response.snapshot;\n\t\t\t\tdetails.scopes = response.scopes;\n\t\t\t\treturn result.text(formatScopes(response.scopes)).done();\n\t\t\t}\n\t\t\tcase \"variables\": {\n\t\t\t\tconst variableReference = params.variable_ref ?? params.scope_id;\n\t\t\t\tif (variableReference === undefined) {\n\t\t\t\t\tthrow new ToolError(\"variables requires variable_ref or scope_id\");\n\t\t\t\t}\n\t\t\t\tconst response = await dapSessionManager.variables(variableReference, combinedSignal, timeoutSec * 1000);\n\t\t\t\tdetails.snapshot = response.snapshot;\n\t\t\t\tdetails.variables = response.variables;\n\t\t\t\treturn result.text(formatVariables(response.variables)).done();\n\t\t\t}\n\t\t\tcase \"disassemble\": {\n\t\t\t\trequireCapability(\"supportsDisassembleRequest\", \"disassembly\");\n\t\t\t\tif (params.instruction_count === undefined) {\n\t\t\t\t\tthrow new ToolError(\"instruction_count is required for disassemble\");\n\t\t\t\t}\n\t\t\t\tconst response = await dapSessionManager.disassemble(\n\t\t\t\t\tresolveDisassemblyReference(params.memory_reference),\n\t\t\t\t\tparams.instruction_count,\n\t\t\t\t\tparams.offset,\n\t\t\t\t\tparams.instruction_offset,\n\t\t\t\t\tparams.resolve_symbols,\n\t\t\t\t\tcombinedSignal,","sourceCodeStart":973,"sourceCodeEnd":1009,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/debug.ts#L973-L1009","documentation":"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.","triggerScenarios":"Calling action=variables with neither params.variable_ref nor params.scope_id set, or both explicitly undefined.","commonSituations":"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.","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"],"exampleFix":"// before\nawait debugTool.run({ action: 'variables', frame_id: 1 }); // frame_id is not a variable reference\n// after\nconst scopes = await debugTool.run({ action: 'scopes', frame_id: 1 });\nawait debugTool.run({ action: 'variables', scope_id: scopes.scopes[0].variablesReference });","handlingStrategy":"type-guard","validationCode":"function canListVariables(params) {\n  const ref = params.variable_ref ?? params.scope_id;\n  return typeof ref === 'number' && ref > 0;\n}\nif (!canListVariables(params)) throw new Error('variables needs a positive variable_ref or scope_id');","typeGuard":"function hasVariableReference(p) {\n  const ref = (p as { variable_ref?: unknown; scope_id?: unknown });\n  return typeof p === 'object' && p !== null\n    && (typeof ref.variable_ref === 'number' && ref.variable_ref > 0\n      || typeof ref.scope_id === 'number' && ref.scope_id > 0);\n}","tryCatchPattern":"try {\n  await debugTool.run({ action: 'variables', ...params });\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes('requires variable_ref or scope_id')) {\n    // call scopes with frame_id first, then retry with a returned variablesReference\n  } else throw err;\n}","preventionTips":["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"],"tags":["debug","dap","parameter-validation","variables"],"backgroundTag":"missing-required-parameter","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}