{"record":{"id":"14b9295278802e06","repo":"XTLS/Xray-core","slug":"could-not-get-process-path-for-pid","errorCode":null,"errorMessage":"could not get process path for PID : ","messagePattern":"could not get process path for PID : ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"common/net/find_process_darwin.go","lineNumber":126,"sourceCode":"\t\t\tbestLevel = matchLevel\n\t\t\tambiguousBest = false\n\t\t\tcontinue\n\t\t}\n\t\tif matchLevel == bestLevel {\n\t\t\tambiguousBest = true\n\t\t}\n\t}\n\n\tif bestLevel == darwinSocketNoMatch {\n\t\treturn 0, \"\", \"\", errors.New(\"process not found for \", network, \" connection from \", srcIP, \":\", srcPort, \" to \", destIP, \":\", destPort)\n\t}\n\tif ambiguousBest {\n\t\treturn 0, \"\", \"\", errors.New(\"ambiguous process match for \", network, \" connection from \", srcIP, \":\", srcPort, \" to \", destIP, \":\", destPort)\n\t}\n\n\tabsPath, err := darwinProcessPath(bestPID)\n\tif err != nil {\n\t\treturn 0, \"\", \"\", errors.New(\"could not get process path for PID \", bestPID, \": \", err)\n\t}\n\n\tabsPath = filepath.ToSlash(absPath)\n\treturn int(bestPID), filepath.Base(absPath), absPath, nil\n}\n\nfunc darwinProcessSocketMatchLevel(pid int32, network string, srcAddr netip.Addr, srcPort uint16, dstAddr netip.Addr, dstPort uint16, hasDstAddr bool) (darwinSocketMatchLevel, error) {\n\tfds, err := darwinProcessFDs(pid)\n\tif err != nil {\n\t\treturn darwinSocketNoMatch, err\n\t}\n\n\tbestLevel := darwinSocketNoMatch\n\tinfo := make([]byte, darwinSocketFDInfoSize)\n\tfor fd := 0; fd+darwinProcFDInfoSize <= len(fds); fd += darwinProcFDInfoSize {\n\t\tfdNumber := int32(darwinReadNativeUint32(fds[fd : fd+4]))\n\t\tfdType := darwinReadNativeUint32(fds[fd+4 : fd+8])\n\t\tif fdType != darwinProcFDTypeSocket {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/common/net/find_process_darwin.go#L108-L144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the wrapped error: ESRCH means the process exited (retry or ignore), EPERM means permission (run elevated or skip)","Retry the whole FindProcess call once for racy exits","Fall back to routing without the process path","For cross-user lookups, run the Xray process with sufficient privileges"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isProcessPathError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"could not get process path\")\n}","tryCatchPattern":"for attempt := 0; attempt < 2; attempt++ {\n    pid, name, path, err = net.FindProcess(netw, srcIP, srcPort, dstIP, dstPort)\n    if err == nil || !isProcessPathError(err) { break }\n    // matched process likely exited; one retry re-enumerates everything\n}","preventionTips":["Distinguish ESRCH (exited, retry) from EPERM (protected, skip) in the wrapped error","Keep process rules best-effort with a single retry budget to bound cost"],"tags":["darwin","process-lookup","race-condition","proc-pidpath"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}