go-delve/delve · error
could not find range-over-func closure parent on the stack
Error message
could not find range-over-func closure parent on the stack
What it means
rangeFuncStackTrace (pkg/proc/stack.go:1301) reconstructs the call chain of a range-over-func iterator by walking frames until it finds the parent function that contains the range statement (rangeParent). If the walk terminates without ever reaching the expected parent function (stage != doneStage), Delve concludes it cannot identify the range-over-func closure parent and returns this error instead of an inconsistent stack. This is a structural detection failure, not necessarily a corrupted stack.
Source
Thrown at pkg/proc/stack.go:1301
return false
}
case lastFrameStage:
frames = append(frames, fr)
stage = doneStage
return false
case doneStage:
return false
}
return true
})
if it.Err() != nil {
return nil, it.Err()
}
if nonMonotonicSP {
return nil, errors.New("corrupted stack (SP not monotonically decreasing)")
}
if stage != doneStage {
return nil, errors.New("could not find range-over-func closure parent on the stack")
}
if len(frames)%2 != 0 {
return nil, errors.New("incomplete range-over-func stacktrace")
}
g.readDefers(frames)
return frames, nil
}
type cachedStack struct {
it *stackIterator
frames []Stackframe
}
type stackCacheKey struct {
goid int64
threadID int
}
View on GitHub (pinned to a23773e6c3)
Solutions
- Rebuild the binary without optimizations (-gcflags='all=-N -l') so closure metadata and rangeParent links survive, then restart the debug session.
- Ensure the binary you are debugging matches the source: recompile and relaunch (dlv debug / dlv exec) rather than attaching to a stale binary.
- Upgrade Delve to a version matching your Go release; range-over-func frame reconstruction depends on compiler-version-specific metadata.
- Use `stack` (regular backtrace) instead of next/stepout to inspect the goroutine, avoiding the range-over-func reconstruction path.
- If reproducible on current Delve + Go, report with a minimal reproducer and the debug log (--log-output=debug).
Example fix
// before: debugging an optimized binary, next inside the iterator body fails // with "could not find range-over-func closure parent on the stack" dlv exec ./app-opt // after: rebuild unoptimized and the parent frame is found go build -gcflags="all=-N -l" -o ./app dlv exec ./app
Defensive patterns
Strategy: fallback
Validate before calling
// Before using next/stepout inside a closure, check the top frame is an expected // range-over-func body (unexported check; from client, verify the frame function // is a closure inside an iterator function rather than assuming parent lookup works). state, _ := client.GetState() topFn := state.CurrentThread.Function.Name() _ = topFn // if this is an optimized build, expect parent lookup to fail
Try / catch
try {
frames = client.Stacktrace(goid, depth)
} catch (err) {
if (strings.Contains(err.Error(), "range-over-func closure parent")) {
// fallback: plain backtrace without range-over-func reconstruction
frames = client.Stacktrace(goid, depth) // or use StacktraceSimple-equivalent
} else {
return err
}
} Prevention
- Rebuild without optimizations before debugging range-over-func code
- Never attach to a binary that has been recompiled since launch
- Pin Delve and Go versions together in CI debug jobs
- Prefer `stack` over next/stepout when stopped in iterator closures on old Delve
When it happens
Trigger: Raised by rangeFuncStackTrace (via setupRangeFrames, StepOut, next) when iterating stack frames no frame matches rangeParent.offset or the rangeParent chain, i.e.: (1) the topmost frame's function has no rangeParent recorded in its DWARF info (wrong or stale binary info); (2) the binary was recompiled after the debugger attached so function offsets in Delve's BinInfo no longer match; (3) the closure body exited the iterator loop normally and the stack contains only frames Delve cannot match (inlined/optimized frames missing closure pointers); (4) fr.Call.Fn == nil encountered at startStage ends the walk immediately with stage != doneStage.
Common situations: Using `next` or `stepout` while stopped inside a range-over-func yield closure; debugging a binary built with heavy optimization (-O, inlined closures) where the closure-to-parent relationship was optimized away; mixing binary versions (build once, recompile, debug old PID with dlv attach); supported-Go-version mismatch where Delve does not understand the newer compiler's closure encoding.
Related errors
- corrupted stack (SP not monotonically decreasing)
- incomplete range-over-func stacktrace
- could not decode first frame
- unable to find function context
- unable to find locals: no debug information present in binar
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/207b0729616e05f6.
Report an issue: GitHub.