{"record":{"id":"4e682c17b73b5480","repo":"go-delve/delve","slug":"incomplete-range-over-func-stacktrace","errorCode":null,"errorMessage":"incomplete range-over-func stacktrace","messagePattern":"incomplete range-over-func stacktrace","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/stack.go","lineNumber":1304,"sourceCode":"\t\t\tframes = append(frames, fr)\n\t\t\tstage = doneStage\n\t\t\treturn false\n\t\tcase doneStage:\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n\tif it.Err() != nil {\n\t\treturn nil, it.Err()\n\t}\n\tif nonMonotonicSP {\n\t\treturn nil, errors.New(\"corrupted stack (SP not monotonically decreasing)\")\n\t}\n\tif stage != doneStage {\n\t\treturn nil, errors.New(\"could not find range-over-func closure parent on the stack\")\n\t}\n\tif len(frames)%2 != 0 {\n\t\treturn nil, errors.New(\"incomplete range-over-func stacktrace\")\n\t}\n\tg.readDefers(frames)\n\treturn frames, nil\n}\n\ntype cachedStack struct {\n\tit     *stackIterator\n\tframes []Stackframe\n}\n\ntype stackCacheKey struct {\n\tgoid     int64\n\tthreadID int\n}\n\ntype stackCache struct {\n\tm map[stackCacheKey]*cachedStack\n}","sourceCodeStart":1286,"sourceCodeEnd":1322,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/stack.go#L1286-L1322","documentation":"After successfully walking to the range-over-func closure parent (stage == doneStage), rangeFuncStackTrace (pkg/proc/stack.go:1304) validates that the reconstructed frame list contains an even number of frames: each yield closure frame must be paired with its caller frame. An odd count means the walk stopped halfway (e.g. an unpaired return frame was added by addRetFrame but the corresponding closure frame was never appended), yielding an incomplete pairing that Delve refuses to return.","triggerScenarios":"Raised by rangeFuncStackTrace (called from setupRangeFrames, StepOut, next) when the frame walk terminates in a state where an odd number of frames accumulated, specifically: (1) the iterator exhausted the stack (it.Next returned false) after appending a return-address frame but before appending the matching closure/caller frame; (2) nested range-over-func statements where the innermost chain was cut off by hitting the top of the goroutine stack or a frame with Call.Fn == nil in a mid stage; (3) frames filtered out by closurePtrOk in normalStage leaving a dangling ret frame.","commonSituations":"Stepping (next/stepout) inside deeply nested range-over-func iterators; debugging near the bottom of a goroutine stack where the iterator chain's parent frames are the goroutine entry; binaries with partially optimized closure metadata so some frames match and others are skipped mid-walk; Go compiler version producing frame sequences Delve's state machine (startStage/normalStage/lastFrameStage) does not anticipate.","solutions":["Retry the stack operation after another stop; transient stop states can leave the walk mid-way and a fresh Stop/Continue cycle usually resolves it.","Rebuild the target with -gcflags='all=-N -l' to preserve closure frames and let the pairing state machine complete.","Update Delve to the version matching your Go toolchain (range-over-func support tracks specific compiler behaviors).","Simplify the debug action: use `stack`/`frames` instead of next/stepout to avoid the pairing reconstruction path.","Reproduce with a minimal range-over-func example and file a Delve bug with the debug log if it persists."],"exampleFix":"null","handlingStrategy":"retry","validationCode":"// Client-side: ensure the goroutine is fully stopped before requesting the stack.\nclient.Halt()\nstate, err := client.GetState()\nif err != nil || !state.Exited && !state.Corrupted { /* proceed */ }","typeGuard":null,"tryCatchPattern":"try {\n    frames = client.Stacktrace(goid, depth)\n} catch (err) {\n    if (strings.Contains(err.Error(), \"incomplete range-over-func stacktrace\")) {\n        client.Halt() // force a clean stop, retry once\n        frames = client.Stacktrace(goid, depth)\n    } else {\n        return err\n    }\n}","preventionTips":["Re-issue stack requests on a fresh stop rather than mid-step","Build with -gcflags='all=-N -l' so closure frames pair correctly","Update Delve when upgrading the Go compiler","Avoid deep nesting of range-over-func iterators in code you must debug with next/stepout"],"tags":["debugger","go","range-over-func","stack-unwinding"],"backgroundTag":"range-over-func-stacktrace-incomplete","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}