go-delve/delve · error
could not recover call injection state for goroutine %d (thr
Error message
could not recover call injection state for goroutine %d (thread %d)
What it means
Delve tracks per-goroutine call-injection state in t.fncallForG[g.ID]. When a thread finishes an injected call, findCallInjectionStateForThread looks up the goroutine's entry; if there is no entry, or the entry's evalStack is nil, the protocol cannot recover what the injected call was doing, so it fails with 'could not recover call injection state'.
Source
Thrown at pkg/proc/fncall.go:1206
if !callinj.evalStack.callInjectionContinue {
err := finishEvalExpressionWithCalls(t, g, callinj.evalStack)
if err != nil {
return done, err
}
done = true
}
}
return done, nil
}
func findCallInjectionStateForThread(t *Target, thread Thread) (*G, *callInjection, error) {
g, err := GetG(thread)
if err != nil {
return nil, nil, fmt.Errorf("could not determine running goroutine for thread %#x currently executing the function call injection protocol: %v", thread.ThreadID(), err)
}
fncallLog("findCallInjectionStateForThread thread=%d goroutine=%d", thread.ThreadID(), g.ID)
notfound := func() error {
return fmt.Errorf("could not recover call injection state for goroutine %d (thread %d)", g.ID, thread.ThreadID())
}
callinj := t.fncallForG[g.ID]
if callinj != nil {
if callinj.evalStack == nil {
return nil, nil, notfound()
}
return g, callinj, nil
}
// In Go 1.15 and later the call injection protocol will switch to a
// different goroutine.
// Here we try to recover the injection goroutine by checking the injection
// thread.
for goid, callinj := range t.fncallForG {
if callinj != nil && callinj.evalStack != nil && callinj.startThreadID != 0 && callinj.startThreadID == thread.ThreadID() {
t.fncallForG[g.ID] = callinj
fncallLog("goroutine %d is the goroutine executing the call injection started in goroutine %d", g.ID, goid)View on GitHub (pinned to a23773e6c3)
Solutions
- Avoid issuing other debugger commands (breakpoints, step, switch goroutine) while a function call injection is in progress.
- Restart the debug session (dlv restart / re-attach) to clear stale injection state, then re-issue the call expression.
- Do not restart or detach/reattach the debugger in the middle of evaluating a call expression.
- Update Delve; if reproducible, file an issue with the command sequence that triggered it.
Defensive patterns
Strategy: try-catch
Try / catch
err := continueAndWaitStop()
if err != nil && strings.Contains(err.Error(), "could not recover call injection state") {
// stale injection state; restart session and re-issue the expression
return restartAndReissue()
}
return err Prevention
- Avoid breakpoints/steps inside functions invoked via call injection
- Never detach/reattach mid-injection
- Wait for an injected expression to finish before issuing other commands
- If state is lost, restart the debug session rather than retrying in place
When it happens
Trigger: A call-injection breakpoint fires for a goroutine whose state was never registered, was already cleaned up (call completed or was cancelled), or whose evalStack was reset — e.g. after a previous step/breakpoint interrupted the injection protocol.
Common situations: User sets a breakpoint inside a function called via an injected call and resumes, corrupting the protocol; debugger restart/reconnect losing in-memory fncallForG while the target still has injection breakpoints; switching goroutines or threads mid-injection; running 'next' or another command while an injected call is in flight.
Related errors
- could not get panic: %v
- could not restore LR: %v
- could not set call receiver: %v
- function %s not found
- unexpected return type for mallocgc call: %v
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/538b570a0451dc3b.
Report an issue: GitHub.