XTLS/Xray-core · warning

could not get process path for PID :

Error message

could not get process path for PID : 

What it means

A best-matching PID was found on macOS, but reading that process's executable path via darwinProcessPath (proc_pidpath) failed. The wrapped error after 'PID <n>:' carries the underlying syscall failure. The match succeeded; only path resolution failed, typically because the process exited or is protected.

Source

Thrown at common/net/find_process_darwin.go:126

			bestLevel = matchLevel
			ambiguousBest = false
			continue
		}
		if matchLevel == bestLevel {
			ambiguousBest = true
		}
	}

	if bestLevel == darwinSocketNoMatch {
		return 0, "", "", errors.New("process not found for ", network, " connection from ", srcIP, ":", srcPort, " to ", destIP, ":", destPort)
	}
	if ambiguousBest {
		return 0, "", "", errors.New("ambiguous process match for ", network, " connection from ", srcIP, ":", srcPort, " to ", destIP, ":", destPort)
	}

	absPath, err := darwinProcessPath(bestPID)
	if err != nil {
		return 0, "", "", errors.New("could not get process path for PID ", bestPID, ": ", err)
	}

	absPath = filepath.ToSlash(absPath)
	return int(bestPID), filepath.Base(absPath), absPath, nil
}

func darwinProcessSocketMatchLevel(pid int32, network string, srcAddr netip.Addr, srcPort uint16, dstAddr netip.Addr, dstPort uint16, hasDstAddr bool) (darwinSocketMatchLevel, error) {
	fds, err := darwinProcessFDs(pid)
	if err != nil {
		return darwinSocketNoMatch, err
	}

	bestLevel := darwinSocketNoMatch
	info := make([]byte, darwinSocketFDInfoSize)
	for fd := 0; fd+darwinProcFDInfoSize <= len(fds); fd += darwinProcFDInfoSize {
		fdNumber := int32(darwinReadNativeUint32(fds[fd : fd+4]))
		fdType := darwinReadNativeUint32(fds[fd+4 : fd+8])
		if fdType != darwinProcFDTypeSocket {

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Read the wrapped error: ESRCH means the process exited (retry or ignore), EPERM means permission (run elevated or skip)
  2. Retry the whole FindProcess call once for racy exits
  3. Fall back to routing without the process path
  4. For cross-user lookups, run the Xray process with sufficient privileges
Defensive patterns

Strategy: retry

Type guard

func isProcessPathError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "could not get process path")
}

Try / catch

for attempt := 0; attempt < 2; attempt++ {
    pid, name, path, err = net.FindProcess(netw, srcIP, srcPort, dstIP, dstPort)
    if err == nil || !isProcessPathError(err) { break }
    // matched process likely exited; one retry re-enumerates everything
}

Prevention

When it happens

Trigger: The matched process exits between the FD scan and the proc_pidpath call (race on short-lived processes); the matched process is a system/sip-protected process where proc_pidpath returns an error for unprivileged callers.

Common situations: Looking up the process for connections owned by short-lived helpers (curl, dig, xargs children) that finish before path resolution; looking up processes owned by other users without elevated privileges.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/14b9295278802e06. Report an issue: GitHub.