{"record":{"id":"538b570a0451dc3b","repo":"go-delve/delve","slug":"could-not-recover-call-injection-state-for-gorouti","errorCode":null,"errorMessage":"could not recover call injection state for goroutine %d (thread %d)","messagePattern":"could not recover call injection state for goroutine (.+?) \\(thread (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/fncall.go","lineNumber":1206,"sourceCode":"\t\tif !callinj.evalStack.callInjectionContinue {\n\t\t\terr := finishEvalExpressionWithCalls(t, g, callinj.evalStack)\n\t\t\tif err != nil {\n\t\t\t\treturn done, err\n\t\t\t}\n\t\t\tdone = true\n\t\t}\n\t}\n\treturn done, nil\n}\n\nfunc findCallInjectionStateForThread(t *Target, thread Thread) (*G, *callInjection, error) {\n\tg, err := GetG(thread)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"could not determine running goroutine for thread %#x currently executing the function call injection protocol: %v\", thread.ThreadID(), err)\n\t}\n\tfncallLog(\"findCallInjectionStateForThread thread=%d goroutine=%d\", thread.ThreadID(), g.ID)\n\tnotfound := func() error {\n\t\treturn fmt.Errorf(\"could not recover call injection state for goroutine %d (thread %d)\", g.ID, thread.ThreadID())\n\t}\n\tcallinj := t.fncallForG[g.ID]\n\tif callinj != nil {\n\t\tif callinj.evalStack == nil {\n\t\t\treturn nil, nil, notfound()\n\t\t}\n\t\treturn g, callinj, nil\n\t}\n\n\t// In Go 1.15 and later the call injection protocol will switch to a\n\t// different goroutine.\n\t// Here we try to recover the injection goroutine by checking the injection\n\t// thread.\n\n\tfor goid, callinj := range t.fncallForG {\n\t\tif callinj != nil && callinj.evalStack != nil && callinj.startThreadID != 0 && callinj.startThreadID == thread.ThreadID() {\n\t\t\tt.fncallForG[g.ID] = callinj\n\t\t\tfncallLog(\"goroutine %d is the goroutine executing the call injection started in goroutine %d\", g.ID, goid)","sourceCodeStart":1188,"sourceCodeEnd":1224,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/fncall.go#L1188-L1224","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := continueAndWaitStop()\nif err != nil && strings.Contains(err.Error(), \"could not recover call injection state\") {\n    // stale injection state; restart session and re-issue the expression\n    return restartAndReissue()\n}\nreturn err","preventionTips":["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"],"tags":["go","debugger","function-call-injection","state-loss"],"backgroundTag":"call-injection-state-lost","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}