go-delve/delve · error

incomplete range-over-func stacktrace

Error message

incomplete range-over-func stacktrace

What it means

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.

Source

Thrown at pkg/proc/stack.go:1304

			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
}

type stackCache struct {
	m map[stackCacheKey]*cachedStack
}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. 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.
  2. Rebuild the target with -gcflags='all=-N -l' to preserve closure frames and let the pairing state machine complete.
  3. Update Delve to the version matching your Go toolchain (range-over-func support tracks specific compiler behaviors).
  4. Simplify the debug action: use `stack`/`frames` instead of next/stepout to avoid the pairing reconstruction path.
  5. Reproduce with a minimal range-over-func example and file a Delve bug with the debug log if it persists.

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

// Client-side: ensure the goroutine is fully stopped before requesting the stack.
client.Halt()
state, err := client.GetState()
if err != nil || !state.Exited && !state.Corrupted { /* proceed */ }

Try / catch

try {
    frames = client.Stacktrace(goid, depth)
} catch (err) {
    if (strings.Contains(err.Error(), "incomplete range-over-func stacktrace")) {
        client.Halt() // force a clean stop, retry once
        frames = client.Stacktrace(goid, depth)
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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