go-delve/delve · error

could not determine running goroutine for thread %#x current

Error message

could not determine running goroutine for thread %#x currently executing the function call injection protocol: %v

What it means

During the function call injection protocol Delve must know which goroutine is running on the thread that hit the injected-call breakpoint, because call-injection state is tracked per goroutine (t.fncallForG). findCallInjectionStateForThread calls GetG(thread) to recover the goroutine; if that fails (runtime structures unreadable, thread not executing Go code, goroutine exited), it throws this error wrapping the underlying GetG failure.

Source

Thrown at pkg/proc/fncall.go:1202

		fncallLog("step for injection on goroutine %d (current) thread=%d (location %s)", g.ID, thread.ThreadID(), loc.Fn.Name)
		t.currentThread = thread
		callinj.evalStack.resume(g)
		if !callinj.evalStack.callInjectionContinue {
			err := finishEvalExpressionWithCalls(t, g, callinj.evalStack)
			if err != nil {
				return done, err
			}
			done = true
		}
	}
	return done, nil
}

func findCallInjectionStateForThread(t *Target, thread Thread) (*G, *callInjection, error) {
	g, err := GetG(thread)
	if err != nil {
		return nil, nil, fmt.Errorf("could not determine running goroutine for thread %#x currently executing the function call injection protocol: %v", thread.ThreadID(), err)
	}
	fncallLog("findCallInjectionStateForThread thread=%d goroutine=%d", thread.ThreadID(), g.ID)
	notfound := func() error {
		return fmt.Errorf("could not recover call injection state for goroutine %d (thread %d)", g.ID, thread.ThreadID())
	}
	callinj := t.fncallForG[g.ID]
	if callinj != nil {
		if callinj.evalStack == nil {
			return nil, nil, notfound()
		}
		return g, callinj, nil
	}

	// In Go 1.15 and later the call injection protocol will switch to a
	// different goroutine.
	// Here we try to recover the injection goroutine by checking the injection
	// thread.

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Retry the call injection; transient scheduling races often resolve on a second attempt.
  2. Ensure the thread is executing Go code (not cgo/runtime) when the call completes; avoid injecting calls that can call into C.
  3. Verify the binary has full Go runtime symbol/DWARF information (don't strip; build with default flags).
  4. Update Delve; check github.com/go-delve/delve for known GetG/GetG issues with your Go version.
Defensive patterns

Strategy: try-catch

Try / catch

err := injectCall(g, fn)
if err != nil && strings.Contains(err.Error(), "could not determine running goroutine") {
    // goroutine may have exited or thread left Go code; reschedule on a live goroutine
    return retryOnLiveGoroutine(fn)
}
return err

Prevention

When it happens

Trigger: GetG fails on a thread that is mid-call-injection — e.g. the goroutine executing the injected call has exited, the thread is running non-Go code (cgo or runtime), or the G struct cannot be read from process memory at the moment the breakpoint fires.

Common situations: Injected call triggers while the target goroutine has died or the thread left Go code; attaching to a process whose runtime state is unreadable; race where the runtime schedules the thread away between injection steps; debugging stripped binaries where runtime symbols are missing.

Related errors


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