go-delve/delve · warning

ep variable not found

Error message

ep variable not found

What it means

On Windows, readSigtrampgoContext (pkg/proc/stack_sigtramp.go:58) recovers the interrupted thread's registers when stopped inside runtime.sigtrampgo by locating the local variable `ep` (a *exceptionpointers passed into sigtrampgo), dereferencing it, and walking to the CONTEXT structure. This error means no variable named `ep` was found in the frame's local scope, so Delve cannot decode the Windows exception context and unwind the stack through the signal handler.

Solutions

  1. Upgrade Delve to the latest release so its expectations about sigtrampgo's `ep` parameter match your Go version.
  2. Rebuild the program keeping symbol/debug info (avoid -ldflags="-s -w"); unoptimized builds (-gcflags='all=-N -l') make locals reliably resolvable.
  3. Ensure dlv attaches to a process built from exactly the binary it was given; relaunch via dlv exec to avoid symbol mismatch.
  4. Continue past the exception or inspect thread state via `regs` as a workaround instead of unwinding through the trampoline.
  5. If reproducible, file a Delve issue with Windows version, Go version, and --log-output=debug output.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// On Windows, before debugging, confirm symbol info is present and versions match:
// go version -m <binary.exe>  (shows build flags; reject -ldflags="-s -w" builds)
// dlv version  vs  go version  (keep within supported range)

Try / catch

try {
    frames = client.Stacktrace(threadID, depth)
} catch (err) {
    if (strings.Contains(err.Error(), "ep variable not found")) {
        // Windows sigtrampgo context unrecoverable; use raw regs or continue
        regs, regErr := client.ListThreadRegs(threadID, false)
        _ = regs
        _ = regErr
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Raised when the debuggee is a Windows process stopped in runtime.sigtrampgo (e.g. after a Windows exception such as an access violation) and scope.Locals(0, "ep") finds nothing named `ep`. Causes: (1) the Go runtime binary lacks DWARF/DWARF-equivalent variable info for `ep` (stripped or highly optimized runtime); (2) binary/process mismatch on attach so the frame scope is resolved against wrong symbols; (3) the Go version's sigtrampgo no longer names the parameter `ep` while the installed Delve is older (or vice versa); (4) the stopped frame is misattributed (PC not actually in sigtrampgo).

Common situations: Debugging a Windows Go program that hit an access violation and the thread stops in the exception trampoline; attaching to a Windows process whose Go runtime was built stripped; running an older Delve against a newer Go release where sigtrampgo's signature/locals changed (Go 1.21+ changes to exception handling); core/exception debugging in IDEs via DAP on Windows.

Related errors


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

Appendix: source

Thrown at pkg/proc/stack_sigtramp.go:58

	}

	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
		}
		switch bi.Arch.Name {
		case "amd64":
			return sigtrampContextWindowsAMD64(it.mem, epaddr)
		case "arm64":
			return sigtrampContextWindowsARM64(it.mem, epaddr)
		default:
			return nil, errors.New("not implemented")
		}
	case "linux":
		addr, err := getctxaddr()
		if err != nil {
			return nil, err
		}

View on GitHub (pinned to a23773e6c3)