go-delve/delve · warning

ctx variable not found

Error message

ctx variable not found

What it means

readSigtrampgoContext (pkg/proc/stack_sigtramp.go:45) recovers the interrupted thread's register state when the debugger stops inside the signal handler trampoline (runtime.sigtrampgo). It looks up the local variable `ctx` in the sigtrampgo frame's scope via DWARF variable information and dereferences it to find the ucontext. This error means no variable named `ctx` could be found in that frame, so Delve cannot reconstruct the registers and unwind out of the signal handler.

Source

Thrown at pkg/proc/stack_sigtramp.go:45

		return nil
	}

	deref := func(v *Variable) (uint64, error) {
		v.loadValue(loadSingleValue)
		if v.Unreadable != nil {
			return 0, fmt.Errorf("could not dereference %s: %v", v.Name, v.Unreadable)
		}
		if len(v.Children) < 1 {
			return 0, fmt.Errorf("could not dereference %s (no children?)", v.Name)
		}
		logger.Debugf("%s address is %#x", v.Name, v.Children[0].Addr)
		return v.Children[0].Addr, nil
	}

	getctxaddr := func() (uint64, error) {
		ctxvar := findvar("ctx")
		if ctxvar == nil {
			return 0, errors.New("ctx variable not found")
		}
		addr, err := deref(ctxvar)
		if err != nil {
			return 0, err
		}
		return addr, nil
	}

	switch bi.GOOS {
	case "windows":
		epvar := findvar("ep")
		if epvar == nil {
			return nil, errors.New("ep variable not found")
		}
		epaddr, err := deref(epvar)
		if err != nil {
			return nil, err
		}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Keep DWARF symbols in the binary: do not pass -ldflags="-s -w"; rebuild with default flags or -gcflags='all=-N -l' for debugging.
  2. Verify the binary being debugged matches the running process (dlv attach) — a stale BinInfo makes the sigtrampgo frame unresolvable; relaunch the session.
  3. Update Delve; newer Go runtimes change where sigtrampgo stores ctx, and Delve must be updated to match your Go version.
  4. As a fallback, read thread registers directly (e.g. `regs` command) instead of relying on the signal-context reconstruction; or continue past the signal.
  5. If you only need the fault location, inspect the SIGSEGV address / goroutine state rather than unwinding through sigtrampgo.

Example fix

// before: stripped binary stops in sigtrampgo, ctx is not in DWARF
go build -ldflags="-s -w" -o app .

// after: keep debug info so the signal context can be recovered
go build -o app .   # or: go build -gcflags="all=-N -l" -o app .
Defensive patterns

Strategy: try-catch

Validate before calling

// Before debugging, ensure the binary retains DWARF info:
// go tool buildid <binary> && go version -m <binary>
// and confirm it was NOT built with -ldflags="-s -w".

Try / catch

try {
    frames = client.Stacktrace(threadID, depth)
} catch (err) {
    if (strings.Contains(err.Error(), "ctx variable not found")) {
        // stopped in sigtrampgo without recoverable signal context;
        // fall back to raw register state or continue past the signal
        regs, regErr := client.ListThreadRegs(threadID, false)
        _ = regs
        _ = regErr
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Triggered when the debuggee is stopped in runtime.sigtrampgo (signal delivery: SIGSEGV, SIGBUS, or Go's own signal-based preemption) on Linux/FreeBSD/Darwin, and scope.Locals(0, "ctx") returns nothing named `ctx`. Causes: (1) Go runtime built without a resolvable DWARF entry for ctx (highly optimized runtime, ctx kept only in registers); (2) binary info mismatch — the sigtrampgo frame is attributed to a different/mismatched binary; (3) the frame is not actually sigtrampgo (misattributed PC), so `ctx` never exists in scope; (4) stripped or partial DWARF in the runtime portion of the binary.

Common situations: Debugging a program that received SIGSEGV and Delve stops the thread inside the signal trampoline; stepping while Go's async preemption signal (SIGURG) lands; core-dump or attach debugging where the stopped PC is in sigtrampgo; debugging a binary whose runtime was compiled with -ldflags="-s -w" or otherwise stripped symbols.

Related errors


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