{"record":{"id":"2e430b6843ff0ec6","repo":"go-delve/delve","slug":"frame-d-only-has-d-deferred-calls","errorCode":null,"errorMessage":"Frame %d only has %d deferred calls","messagePattern":"Frame (.+?) only has (.+?) deferred calls","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/eval.go","lineNumber":120,"sourceCode":"\tif g != nil {\n\t\tif g.Thread != nil {\n\t\t\tthreadID = g.Thread.ThreadID()\n\t\t}\n\t\tlocs, err = GoroutineStacktrace(dbp, g, frame+1, opts)\n\t} else {\n\t\tlocs, err = ThreadStacktrace(dbp, ct, frame+1)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif frame >= len(locs) {\n\t\treturn nil, fmt.Errorf(\"Frame %d does not exist in goroutine %d\", frame, gid)\n\t}\n\n\tif deferCall > 0 {\n\t\tif deferCall-1 >= len(locs[frame].Defers) {\n\t\t\treturn nil, fmt.Errorf(\"Frame %d only has %d deferred calls\", frame, len(locs[frame].Defers))\n\t\t}\n\n\t\td := locs[frame].Defers[deferCall-1]\n\t\tif d.Unreadable != nil {\n\t\t\treturn nil, d.Unreadable\n\t\t}\n\n\t\treturn d.EvalScope(dbp, ct)\n\t}\n\n\treturn FrameToScope(dbp, dbp.Memory(), g, threadID, locs[frame:]...), nil\n}\n\n// FrameToScope returns a new EvalScope for frames[0].\n// If frames has at least two elements all memory between\n// frames[0].Regs.SP() and frames[1].Regs.CFA will be cached.\n// Otherwise all memory between frames[0].Regs.SP() and frames[0].Regs.CFA\n// will be cached.","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/eval.go#L102-L138","documentation":"When ConvertEvalScope is called with deferCall > 0, the scope is made relative to the deferCall-th deferred call of the given frame. The stack is walked with StacktraceReadDefers; if the frame has fewer deferred calls than requested (deferCall-1 >= len(locs[frame].Defers)), this error is returned because that deferred call does not exist.","triggerScenarios":"ConvertEvalScope(dbp, gid, frame, deferCall) where frame's Defers slice has fewer entries than deferCall; e.g. asking for the 2nd deferred call when the frame only registered one defer, or requesting deferCall > 0 on a frame with no pending defers at all.","commonSituations":"Client UIs listing deferred calls from an older stop event and re-evaluating after execution moved past a deferred function; miscounting defers (defers are listed innermost-first, index is 1-based); evaluating a defer after its frame returned.","solutions":["Enumerate the frame's Defers via a stacktrace with StacktraceReadDefers and pick deferCall within 1..len(Defers).","Remember deferCall is 1-based: use deferCall = index+1 of the desired defer, not the raw index.","Re-read defers at the current stop point; a defer may already have run since it was listed.","Fall back to deferCall = 0 (normal frame scope) when the frame has no pending defers."],"exampleFix":"// before\nscope, err := proc.ConvertEvalScope(t, gid, frame, 3)\n// after\nlocs, _ := proc.GoroutineStacktrace(t, g, frame+1, proc.StacktraceReadDefers)\ndeferCall := 0\nif len(locs) > frame && len(locs[frame].Defers) >= 3 { deferCall = 3 }\nscope, err := proc.ConvertEvalScope(t, gid, frame, deferCall)","handlingStrategy":"validation","validationCode":"locs, err := proc.GoroutineStacktrace(t, g, frame+1, proc.StacktraceReadDefers)\nif err != nil { return err }\nif deferCall < 1 || len(locs) <= frame || deferCall > len(locs[frame].Defers) {\n    return fmt.Errorf(\"frame %d has %d defers, requested %d\", frame, len(locs[frame].Defers), deferCall)\n}","typeGuard":"func deferCallExists(locs []proc.Stackframe, frame, deferCall int) bool {\n    return frame >= 0 && frame < len(locs) && deferCall >= 1 && deferCall <= len(locs[frame].Defers)\n}","tryCatchPattern":"scope, err := proc.ConvertEvalScope(t, gid, frame, deferCall)\nif err != nil && strings.Contains(err.Error(), \"deferred calls\") {\n    scope, err = proc.ConvertEvalScope(t, gid, frame, 0) // fall back to normal frame scope\n}","preventionTips":["List Defers with StacktraceReadDefers at the current stop point before choosing deferCall","Remember deferCall is 1-based, defers are indexed innermost-first","Re-read defers after each resume; they may have already executed","Fall back to deferCall=0 when in doubt"],"tags":["go","debugger","defer","eval-scope"],"backgroundTag":"defer-index-out-of-range","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}