go-delve/delve · error
could not determine executable path: %v
Error message
could not determine executable path: %v
What it means
During gdbserial connection initialization, Delve must learn the inferior's executable path when the user did not supply one (attach mode). It first tries qXfer:exec-file:read (gdb way), then qProcessInfo (lldb way); if a non-'unsupported' protocol error comes back from readExecFile, the connection is closed and this error is thrown wrapping the underlying cause.
Source
Thrown at pkg/proc/gdbserial/gdbserver.go:719
func (p *gdbProcess) initialize(path, cmdline string, debugInfoDirs []string, stopReason proc.StopReason) (*proc.TargetGroup, error) {
var err error
if path == "" {
// If we are attaching to a running process and the user didn't specify
// the executable file manually we must ask the stub for it.
// We support both qXfer:exec-file:read:: (the gdb way) and calling
// qProcessInfo (the lldb way).
// Unfortunately debugserver on macOS supports neither.
path, err = p.conn.readExecFile()
if err != nil {
if isProtocolErrorUnsupported(err) {
_, path, err = queryProcessInfo(p, p.Pid())
if err != nil {
p.conn.conn.Close()
return nil, err
}
} else {
p.conn.conn.Close()
return nil, fmt.Errorf("could not determine executable path: %v", err)
}
}
}
if path == "" {
// try using jGetLoadedDynamicLibrariesInfos which is the only way to do
// this supported on debugserver (but only on macOS >= 12.10)
images, _ := p.conn.getLoadedDynamicLibraries()
for _, image := range images {
if image.MachHeader.FileType == macho.TypeExec {
path = image.Pathname
break
}
}
}
err = p.updateThreadList(&threadUpdater{p: p}, nil)
if err != nil {View on GitHub (pinned to a23773e6c3)
Solutions
- Pass the executable path explicitly when attaching (dlv attach <pid> with the binary, or the gdbserial API's path argument) so readExecFile is never called
- Check the wrapped '%v' cause to see the actual protocol error and fix the stub/connection
- Use a known-good stub (recent gdbserver, lldb-server, or macOS debugserver) that supports qXfer:exec-file:read or qProcessInfo
- Verify the connection is stable (no proxy/firewall mangling packets) since transport errors surface here
Example fix
// before target, err := client.Connect(pid, "") // empty path forces exec-file query // after target, err := client.Connect(pid, "/path/to/inferior") // path supplied, no exec-file lookup
Defensive patterns
Strategy: validation
Validate before calling
if path == "" {
if fi, err := os.Stat(fmt.Sprintf("/proc/%d/exe", pid)); err == nil {
path, _ = os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
}
}
// pass resolved path to Connect so readExecFile is skipped Try / catch
tgt, err := client.Connect(pid, path)
if err != nil && strings.Contains(err.Error(), "could not determine executable path") {
// fall back: supply the path explicitly and reconnect
tgt, err = client.Connect(pid, resolvedPath)
} Prevention
- Always pass the executable path explicitly when attaching
- Verify the stub supports qXfer:exec-file:read or qProcessInfo before connect
- Read the wrapped cause (%v) to distinguish protocol bugs from unsupported features
- Test attachments against your stub version in CI
When it happens
Trigger: Connecting to a stub (gdbserver/debugserver/lldb-server/rr) in attach mode with an empty executable path where the qXfer:exec-file:read packet fails with a real protocol error (not a plain 'unsupported' reply) — e.g. malformed stub reply, connection-level failure, or a stub that returns an error other than the empty unsupported response.
Common situations: Attaching to a process through a nonstandard or buggy GDB remote stub; a stub that replies to qXfer:exec-file with an error string instead of the expected empty/unsupported packet; custom or older debugserver builds; networked gdbserver connections that corrupt replies.
Related errors
- qMemoryRegionInfo response wrapped around the address space
- too many transmit attempts
- malformed qfThreadInfo response
- malformed qMemoryRegionInfo response packet (start): %v in %
- malformed qMemoryRegionInfo response packet (size): %v in %s
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/2798215856a58327.
Report an issue: GitHub.