go-delve/delve · error
corrupted stack (SP not monotonically decreasing)
Error message
corrupted stack (SP not monotonically decreasing)
What it means
This error is produced by rangeFuncStackTrace in pkg/proc/stack.go:1298 when, while walking a goroutine stack to reconstruct the frame chain of a range-over-func (range 2.0) statement, the stack pointer of a successive frame is lower than the previous frame's SP. A valid Go stack must grow monotonically downward, so a non-decreasing SP walk indicates the unwind is unreliable (stack corruption, wrong frame pointers, or corrupted memory). Delve aborts the reconstruction rather than returning a bogus stack.
Source
Thrown at pkg/proc/stack.go:1298
frames = nil
addRetFrame = false
stage = doneStage
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 int64View on GitHub (pinned to a23773e6c3)
Solutions
- Retry the operation: stop the target again and re-issue `next`/`stepout`/stack request, since transient states (e.g. mid stack-copy) can produce this.
- Disable optimizations when building the debuggee (go build with -gcflags=all='-N -l') so frame layouts and closure metadata match what Delve expects.
- Upgrade Delve to the latest version compatible with your Go toolchain; range-over-func support is recent and version-sensitive.
- Run with --log-output=debug (debugger log) to capture the SP values of the offending frames and file a Delve issue if reproducible.
- If the process was attached after a crash or under memory corruption, verify the program itself is not corrupting its stack (e.g. unsafe/cgo bugs).
Example fix
// before: next/stepout inside a range-over-func closure crashes the stack walk // (nothing to change in user code; build-side fix) // after: rebuild the debuggee without optimizations before debugging go build -gcflags="all=-N -l" -o app ./cmd/app dlv exec ./app
Defensive patterns
Strategy: retry
Validate before calling
// No pre-call validation API exists; guard at call time in the client/driver.
// Re-request the stack on a fresh stop instead of caching frames across stops.
frames, err := dbg.Stacktrace(goroutineID, depth)
if err != nil && strings.Contains(err.Error(), "SP not monotonically decreasing") {
// transient/unreliable unwind: re-stop and retry once
} Try / catch
try {
frames = client.Stacktrace(goid, depth)
} catch (err) {
if (strings.Contains(err.Error(), "corrupted stack")) {
time.Sleep(50 * time.Millisecond) // let target settle
frames = client.Stacktrace(goid, depth) // single retry on fresh stop
} else {
return err
}
} Prevention
- Build the debuggee unoptimized: -gcflags='all=-N -l'
- Keep Delve version matched to your Go toolchain version
- Do not cache stack frames across Continue/Stop cycles
- Avoid attaching to processes suspected of memory corruption (unsafe/cgo)
When it happens
Trigger: Happens inside rangeFuncStackTrace (called from setupRangeFrames, StepOut, and next) when it.stacktraceFunc walks frames and detects fr.Regs.SP() < prev.Regs.SP(). This occurs when: (1) the range-over-func closure body was stopped in, but the frame chain (FP/BP/SP) cannot be unwound consistently; (2) the goroutine stack was grown or moved concurrently and stale SP values were cached; (3) memory corruption or reading a thread whose stack was reused; (4) optimizing compiler versions emitting frame layouts Delve cannot model.
Common situations: Debugging Go programs that use range-over-func iterators (GOEXPERIMENT=rangefunc or Go 1.23+) with `next`/`stepout` inside a yield closure; debugging an optimized binary where closures were inlined or stack-allocated in ways the DWARF does not describe; attaching to a process that was mid-stack-growth when stopped; old Delve versions combined with newer Go compilers.
Related errors
- could not find range-over-func closure parent on the stack
- 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/3ddff88867ddc6e5.
Report an issue: GitHub.