go-delve/delve · error

Could not attach to pid %d: this could be caused by a kernel

Error message

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

What it means

Specific EPERM diagnostic: the kernel Yama security module restricts ptrace to descendants, so attaching to an unrelated process fails with EPERM. The debugger reads /proc/sys/kernel/yama/ptrace_scope and, if it is non-zero, reports this as the likely cause.

Source

Thrown at service/debugger/debugger_linux.go:27

	"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)
			}

			// check if the process is already being traced
			statusfh, err := os.Open(fmt.Sprintf("/proc/%d/status", pid))
			if err != nil {
				return fallbackerr
			}
			defer statusfh.Close()
			scan := bufio.NewScanner(statusfh)

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Write 0 to /proc/sys/kernel/yama/ptrace_scope: echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
  2. Launch the target as a child of delve (dlv debug / dlv exec) instead of attaching
  3. Attach as root (sudo dlv attach) which bypasses Yama restrictions
  4. Make the setting permanent via sysctl: kernel.yama.ptrace_scope=0

Example fix

// before
dlv attach 12345 // fails with EPERM
// after (shell)
sudo sysctl -w kernel.yama.ptrace_scope=0
dlv attach 12345
Defensive patterns

Strategy: validation

Validate before calling

bs, _ := os.ReadFile("/proc/sys/kernel/yama/ptrace_scope")
yamaBlocked := len(bs) > 0 && bs[0] != '0'

Try / catch

err := debugger.Attach(pid, []string{}, nil)
if err != nil && strings.Contains(err.Error(), "yama/ptrace_scope") {
    // surface instruction to run: echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
}

Prevention

When it happens

Trigger: 'dlv attach <pid>' or debugger.Attach on a process that is not a child of the debugger while /proc/sys/kernel/yama/ptrace_scope contains a value != '0'.

Common situations: Default Ubuntu/Debian kernels (ptrace_scope=1); CI containers with hardened settings; attaching to an already-running service started by another session.

Related errors


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