go-delve/delve · error
call is only supported with topmost stack frame
Error message
call is only supported with topmost stack frame
What it means
The DAP server's injected function-call (call) evaluation only supports expressions evaluated in the topmost stack frame. If the frameId refers to a parent frame (frame > 0), it returns this error, because variables of parent frames would silently be evaluated in the wrong (topmost) context, producing misleading results.
Source
Thrown at service/dap/server.go:3374
// these contexts are used to copy the value.
if ctxt == "clipboard" || ctxt == "variables" {
opts |= showFullValue
}
exprVal, exprRef := s.convertVariableWithOpts(exprVar, fmt.Sprintf("(%s)", request.Arguments.Expression), opts, goid, frame)
response.Body = dap.EvaluateResponseBody{Result: exprVal, Type: s.getTypeIfSupported(exprVar), VariablesReference: exprRef, IndexedVariables: getIndexedVariableCount(exprVar), NamedVariables: getNamedVariableCount(exprVar)}
}
s.send(response)
}
func (s *Session) doCall(goid, frame int, expr string) (*api.DebuggerState, []*proc.Variable, error) {
// This call might be evaluated in the context of the frame that is not topmost
// if the editor is set to view the variables for one of the parent frames.
// If the call expression refers to any of these variables, unlike regular
// expressions, it will evaluate them in the context of the topmost frame,
// and the user will get an unexpected result or an unexpected symbol error.
// We prevent this but disallowing any frames other than topmost.
if frame > 0 {
return nil, nil, errors.New("call is only supported with topmost stack frame")
}
stateBeforeCall, err := s.debugger.State( /*nowait*/ true)
if err != nil {
return nil, nil, err
}
// The return values of injected function calls are volatile.
// Load as much useful data as possible.
// TODO: investigate whether we need to increase other limits. For example,
// the return value is a pointer to a temporary object, which can become
// invalid by other injected function calls. Do we care about such use cases?
loadCfg := s.loadConfig()
loadCfg.MaxStringLen = maxStringLenInCallRetVars
// TODO(polina): since call will resume execution of all goroutines,
// we should do this asynchronously and send a continued event to the
// editor, followed by a stop event when the call completes.
state, err := s.debugger.Command(&api.DebuggerCommand{
Name: api.Call,View on GitHub (pinned to a23773e6c3)
Solutions
- Select the topmost (innermost) stack frame before issuing the call expression
- Evaluate the call after stepping until the relevant frame is topmost
- Rewrite the expression to only use variables accessible from the topmost frame, or evaluate plain (non-call) expressions which work on any frame
- If the call must run in an outer context, stop at a breakpoint located in that frame instead
Example fix
// before: evaluate with frameId of frame 2
{expression: 'helper(x)', frameId: parentFrameId}
// after: use topmost frame or a non-call expression
{expression: 'helper(x)', frameId: topFrameId}
{expression: 'x', frameId: parentFrameId} // plain reads are allowed on any frame Defensive patterns
Strategy: validation
Validate before calling
// only send call expressions when the selected frame is the topmost
if selectedFrameIndex != 0 && isLikelyCall(expr) {
return errors.New("select the topmost frame to evaluate calls")
} Try / catch
if err.Error() == "call is only supported with topmost stack frame" {
// re-issue the evaluation with the topmost frameId
} Prevention
- Bind call evaluation in the UI to the topmost frame only
- Allow arbitrary-frame evaluation only for plain (non-call) expressions
- Educate users that calls always run in the topmost frame context
When it happens
Trigger: Invoking a function call from a Watch/REPL/evaluate request while a non-topmost frame is selected (stackFramesId pointing to frame index > 0); drag-and-drop of a call expression onto a parent frame in the Variables view.
Common situations: Developers stopped deep in a call stack selecting an outer frame and typing a function call into the debug console; IDE watch expressions that reference a call while an ancestor frame is active.
Related errors
- terminated
- call stopped
- function calls not allowed without using 'call'
- literal can not be allocated because function calls are not
- function calls not supported by this version of Go
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/99efb1f08710ffcf.
Report an issue: GitHub.