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

  1. Rebuild the binary without optimizations (-gcflags='all=-N -l') so closure metadata and rangeParent links survive, then restart the debug session.
  2. Ensure the binary you are debugging matches the source: recompile and relaunch (dlv debug / dlv exec) rather than attaching to a stale binary.
  3. Upgrade Delve to a version matching your Go release; range-over-func frame reconstruction depends on compiler-version-specific metadata.
  4. Use `stack` (regular backtrace) instead of next/stepout to inspect the goroutine, avoiding the range-over-func reconstruction path.
  5. 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

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


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/207b0729616e05f6. Report an issue: GitHub.