go-delve/delve · error
could not attach to pid %d: %s
Error message
could not attach to pid %d: %s
What it means
Generic fallback message produced by attachErrorMessageLinux in service/debugger/debugger_linux.go when 'dlv attach <pid>' fails with an error that is not a recognized syscall.Errno, or when none of the specific diagnostics (yama ptrace_scope, ownership, TracerPid) apply. It wraps the underlying ptrace/PTRACE_ATTACH error from the native backend.
Source
Thrown at service/debugger/debugger_linux.go:19
package debugger
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"syscall"
)
func init() {
attachErrorMessage = attachErrorMessageLinux
}
//lint:file-ignore ST1005 errors here can be capitalized
func attachErrorMessageLinux(pid int, err error) error {
fallbackerr := fmt.Errorf("could not attach to pid %d: %s", pid, err)
if serr, ok := err.(syscall.Errno); ok {
switch serr {
case syscall.EPERM:
// check if ptrace of non-child processes is disabled
bs, err := os.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
if err == nil && len(bs) >= 1 && bs[0] != '0' {
// Yama documentation: https://www.kernel.org/doc/Documentation/security/Yama.txt
return fmt.Errorf("Could not attach to pid %d: this could be caused by a kernel security setting, try writing \"0\" to /proc/sys/kernel/yama/ptrace_scope", pid)
}
// check if the pid belongs to a different process
fi, err := os.Stat(fmt.Sprintf("/proc/%d", pid))
if err != nil {
return fallbackerr
}
if fi.Sys().(*syscall.Stat_t).Uid != uint32(os.Getuid()) {
return fmt.Errorf("Could not attach to pid %d: current user does not own the process", pid)
}View on GitHub (pinned to a23773e6c3)
Solutions
- Verify the pid exists and is alive: check /proc/<pid> before attaching
- Retry attach as root or with CAP_SYS_PTRACE to rule out permission issues
- Check the wrapped underlying error text for the real cause
- Re-run in the same container/namespace as the target process
Example fix
// before dlv attach 12345 // after # confirm target exists first kill -0 12345 && dlv attach 12345
Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := os.Stat(fmt.Sprintf("/proc/%d", pid)); err != nil { return fmt.Errorf("pid %d not alive", pid) } Type guard
if errno, ok := err.(syscall.Errno); ok { /* handle EPERM/ESRCH specifically */ } Try / catch
err := debugger.Attach(pid, []string{}, nil)
if err != nil && strings.Contains(err.Error(), "could not attach to pid") {
// inspect wrapped cause, check /proc/<pid>, retry as root
} Prevention
- Check /proc/<pid> existence before attaching
- Run the debugger with sufficient privileges (root or CAP_SYS_PTRACE)
- Attach within the same container/PID namespace as the target
- Keep only one tracer per process
When it happens
Trigger: Calling debugger.Attach (or 'dlv attach <pid>') on Linux where the underlying ptrace attach returns an error other than EPERM, or EPERM whose cause is not yama ptrace_scope, wrong-owner, or already-traced.
Common situations: Attaching to a process that already exited between listing and attaching; attaching to a pid in another PID namespace or container; seccomp/LSM policies blocking ptrace; stale pid.
Related errors
- could not attach to pid %d: already being debugged by pid %d
- process must be stopped in order to kill it
- waiting for target execve failed: %s
- could not read proc stat: %v
- no match found using regexp '%s' in /proc/%d/stat
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/685c99d7446c6c37.
Report an issue: GitHub.