go-delve/delve · error
terminated
Error message
terminated
What it means
During injected function-call evaluation, if the process exits (or terminates) while the call is in progress, the session detects it via processExited(state, err), emits exited/terminated events to the client, and then returns the sentinel error 'terminated' to the evaluate caller. It signals that the call never completed because the debuggee died.
Solutions
- Do not evaluate calls that terminate the process (os.Exit, log.Fatal, panic)
- Re-launch the debuggee; the session is over once the process exits
- If calls near the end of main keep terminating, place breakpoints earlier or guard with runtime checks
- Inspect the call's side effects in a sandbox/test instead of evaluating them in the live target
Example fix
// before (debug console, terminates target)
os.Exit(1)
// after
fmt.Println("would exit") // or set a breakpoint instead of calling exit Defensive patterns
Strategy: try-catch
Validate before calling
// pre-screen dangerous calls before injecting
blocked := []string{"os.Exit", "log.Fatal", "panic"}
for _, b := range blocked {
if strings.HasPrefix(expr, b) { return fmt.Errorf("refusing %q", b) }
} Try / catch
if err.Error() == "terminated" {
// the debuggee exited: tear down the session and relaunch before any further requests
} Prevention
- Never evaluate process-terminating calls from the debug console
- Avoid injected calls near program exit points
- Treat a 'terminated' result as final — re-launch to continue debugging
When it happens
Trigger: The injected call causes the target process to exit (e.g. calling os.Exit or a function that panics fatally); the debuggee is killed externally during a call; the program finishes/naturally exits while a call is being injected at the end of main.
Common situations: Evaluating calls like os.Exit(1) or log.Fatal from the debug console; long-running call racing with program termination at the last breakpoint in main; crashes triggered by the injected call's side effects.
Related errors
- call is only supported with topmost stack frame
- call stopped
- another launch request is in progress
- backend does not support function calls
- breakpoint already exists
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/8b113f70c6ad21b1.
Report an issue: GitHub.
Appendix: source
Thrown at service/dap/server.go:3403
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,
ReturnInfoLoadConfig: api.LoadConfigFromProc(&loadCfg),
Expr: expr,
UnsafeCall: false,
GoroutineID: int64(goid),
WithEvents: true,
}, nil, s.conn.closedChan, s.convertDebuggerEvent)
if processExited(state, err) {
s.preTerminatedWG.Wait()
s.sendExitedEvent(state, err)
s.send(&dap.TerminatedEvent{Event: *s.newEvent("terminated")})
return nil, nil, errors.New("terminated")
}
if err != nil {
return nil, nil, err
}
// After the call is done, the goroutine where we injected the call should
// return to the original stopped line with return values. However,
// it is not guaranteed to be selected due to the possibility of the
// of simultaneous breakpoints. Therefore, we check all threads.
var retVars []*proc.Variable
found := false
for _, t := range state.Threads {
if t.GoroutineID == stateBeforeCall.SelectedGoroutine.ID &&
t.Line == stateBeforeCall.SelectedGoroutine.CurrentLoc.Line && t.CallReturn {
found = true
// The call completed. Get the return values.
retVars, err = s.debugger.FindThreadReturnValues(t.ID, loadCfg)
if err != nil {View on GitHub (pinned to a23773e6c3)