go-delve/delve · critical
could not fork/exec
Error message
could not fork/exec
What it means
Delve's Darwin native backend launches the debuggee via a C fork/exec helper (fork_exec) that returns the child pid. If the returned pid is <= 0 the helper failed to create or exec the child process, and Launch wraps this condition in the generic message "could not fork/exec". It means the inferior never started, so no debugging session exists.
Source
Thrown at pkg/proc/native/proc_darwin.go:88
dbp := newProcess(0)
defer func() {
if err != nil && dbp.pid != 0 {
_ = detachWithoutGroup(dbp, true)
}
}()
var pid int
dbp.execPtraceFunc(func() {
wd := C.CString(wd)
defer C.free(unsafe.Pointer(wd))
ret := C.fork_exec(argv0, &argvSlice[0], C.int(len(argvSlice)),
wd,
&dbp.os.task, &dbp.os.portSet, &dbp.os.exceptionPort,
&dbp.os.notificationPort)
pid = int(ret)
})
if pid <= 0 {
return nil, fmt.Errorf("could not fork/exec")
}
dbp.pid = pid
dbp.childProcess = true
for i := range argvSlice {
C.free(unsafe.Pointer(argvSlice[i]))
}
// Initialize enough of the Process state so that we can use resume and
// trapWait to wait until the child process calls execve.
for {
task := C.get_task_for_pid(C.int(dbp.pid))
// The task_for_pid call races with the fork call. This can
// result in the parent task being returned instead of the child.
if task != dbp.os.task {
err = dbp.updateThreadListForTask(task)
if err == nil {
breakView on GitHub (pinned to a23773e6c3)
Solutions
- Verify the target binary path exists and is executable (ls -l, chmod +x) before launching.
- Check the argv slice passed to Launch is non-empty and argv[0] is the program path.
- Try building with `dlv debug` instead of `dlv exec <bin>` to rule out a stale/broken binary.
- Check macOS security settings / SIP and antivirus software that may block ptrace-style helpers.
- Rebuild Delve for your macOS version; older C helpers break on newer SDKs.
Example fix
// before dlv exec ./notbuilt // after go build -gcflags="all=-N -l" -o ./app ./cmd/app dlv exec ./app
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(binPath)
if err != nil || info.IsDir() {
return fmt.Errorf("binary %s missing: %w", binPath, err)
}
if info.Mode()&0o111 == 0 {
return fmt.Errorf("binary %s is not executable", binPath)
} Try / catch
tgt, err := proc.Launch(cmd, wd, false, "", [], "", logger)
if err != nil && strings.Contains(err.Error(), "could not fork/exec") {
// inspect cmd[0], permissions, and macOS security settings before retrying
} Prevention
- Always build the target with debug flags (-gcflags="all=-N -l") before launching.
- Validate the executable path and mode before calling Launch.
- Keep dlv rebuilt/signed for the current macOS version.
- Avoid empty argv slices; argv[0] must be the program path.
When it happens
Trigger: Calling dlv debug/launch on macOS when the C.fork_exec call in proc_darwin.go fails: bad executable path, missing execute permission, argv/env marshaling problems, or resource limits preventing fork. Detected by `pid <= 0` immediately after the fork/exec call.
Common situations: Debugging a binary path that doesn't exist or isn't executable; macOS security (SIP/hardened runtime) blocking the fork helper; running out of process descriptors; passing a command string with an empty argv slice.
Related errors
- setpgid
- ptrace
- can not run under Rosetta, check that the installed build of
- follow exec not implemented
- native backend disabled during compilation
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/0ebd8484dbce40b5.
Report an issue: GitHub.