go-delve/delve · error

no match found using regexp '%s' in /proc/%d/stat

Error message

no match found using regexp '%s' in /proc/%d/stat

What it means

After reading /proc/<pid>/stat, delve applies the regexp "<pid>\\s*\\((.*)\\)" to extract the command name. If FindSubmatch finds no match, it returns this error including the full expression and pid. This means the stat file's first field is not the expected pid or the file is malformed/truncated.

Source

Thrown at pkg/proc/native/proc_linux.go:288

	comm, err := os.ReadFile(fmt.Sprintf("/proc/%d/comm", dbp.pid))
	if err == nil {
		// removes newline character
		comm = bytes.TrimSuffix(comm, []byte("\n"))
	}

	if len(comm) <= 0 {
		stat, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", dbp.pid))
		if err != nil {
			return "", fmt.Errorf("could not read proc stat: %v", err)
		}
		expr := fmt.Sprintf("%d\\s*\\((.*)\\)", dbp.pid)
		rexp, err := regexp.Compile(expr)
		if err != nil {
			return "", fmt.Errorf("regexp compile error: %v", err)
		}
		match := rexp.FindSubmatch(stat)
		if match == nil {
			return "", fmt.Errorf("no match found using regexp '%s' in /proc/%d/stat", expr, dbp.pid)
		}
		comm = match[1]
	}
	dbp.os.comm = strings.ReplaceAll(string(comm), "%", "%%")

	return getCmdLine(dbp.pid), nil
}

func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams {
	if dbp.os.ebpf == nil {
		return nil
	}
	return dbp.os.ebpf.GetBufferedTracepoints()
}

// kill kills the target process.
func (procgrp *processGroup) kill(dbp *nativeProcess) error {
	if ok, _ := dbp.Valid(); !ok {

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Re-run the attach; a race with process exit is the most common cause.
  2. Inspect /proc/<pid>/stat manually to confirm the first field equals the pid.
  3. If running under gVisor/LXC or other sandboxed procfs, test on a standard kernel or use a newer sandbox runtime with conformant procfs.
  4. Run delve as root so it reads the correct process's stat rather than failing on visibility tricks.

Example fix

// before
_ = debugger.Attach(pid, nil) // no match found using regexp '1234\s*\((.*)\)' in /proc/1234/stat

// after
stat, _ := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid))
if !strings.HasPrefix(string(stat), strconv.Itoa(pid)+" ") {
    return fmt.Errorf("pid %d vanished or was reused before attach", pid)
}
_ = debugger.Attach(pid, nil)
Defensive patterns

Strategy: retry

Validate before calling

// confirm stat file shape matches the pid before attach
func statLooksSane(pid int) bool {
    b, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid))
    return err == nil && strings.HasPrefix(string(b), strconv.Itoa(pid)+" ")
}

Try / catch

err := debugger.Attach(pid, nil)
if err != nil && strings.Contains(err.Error(), "no match found using regexp") {
    // likely exit/pid-reuse race or non-standard procfs; retry once
    err = debugger.Attach(pid, nil)
}

Prevention

When it happens

Trigger: initialize's comm fallback parses a stat file whose contents do not start with the traced pid — typically because the process exited and the pid was reused, or a race left a truncated read, or the kernel is not Linux-standard procfs (LXC/gVisor variants).

Common situations: Attaching in containers/sandboxes (gVisor, LXC) with non-conforming procfs; pid churn in busy CI environments; reading /proc for a zombie or being-reaped process whose stat layout differs.

Related errors


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