{"record":{"id":"4c52f2cdf2fea952","repo":"benfred/py-spy","slug":"failed-to-get-subprocesses-4c52f2","errorCode":null,"errorMessage":"failed to get subprocesses","messagePattern":"failed to get subprocesses","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/sampler.rs","lineNumber":155,"sourceCode":"                    \"No python processes found in process {} or any of its subprocesses\",\n                    pid\n                ));\n            }\n            std::thread::sleep(std::time::Duration::from_millis(100));\n        }\n\n        // Create a new thread to periodically monitor for new child processes, and update\n        // the procesess map\n        let spies = Arc::new(Mutex::new(spies));\n        let monitor_spies = spies.clone();\n        let monitor_config = config.clone();\n        std::thread::spawn(move || {\n            while process.exe().is_ok() {\n                match monitor_spies.lock() {\n                    Ok(mut spies) => {\n                        for (childpid, parentpid) in process\n                            .child_processes()\n                            .expect(\"failed to get subprocesses\")\n                        {\n                            if spies.contains_key(&childpid) {\n                                continue;\n                            }\n                            match PythonSpyThread::new(childpid, Some(parentpid), &monitor_config) {\n                                Ok(spy) => {\n                                    spies.insert(childpid, spy);\n                                }\n                                Err(e) => {\n                                    warn!(\"Failed to create spy for {}: {}\", childpid, e);\n                                }\n                            }\n                        }\n                    }\n                    Err(e) => {\n                        error!(\"Failed to acquire lock: {}\", e);\n                    }\n                }","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/benfred/py-spy/blob/32080cc0c22bc23938541dfa7dabb6090e40be14/src/sampler.rs#L137-L173","documentation":"In Sampler::new_subprocess_sampler, a background thread periodically calls process.child_processes() to discover new child interpreters while recording with --subprocesses. A failed enumeration panics on that thread with \"failed to get subprocesses\", aborting the sampling session.","triggerScenarios":"Running `py-spy record --subprocesses` when child_processes() fails during sampling — the target or its children exited mid-record, permissions on process metadata changed, or an OS enumeration API returned an error mid-session.","commonSituations":"Long recordings where the parent exits after children finish (common with shell wrappers), jobs that kill/restart worker processes, or recordings started as root that lose privileges or vice versa.","solutions":["Keep the parent process alive for the whole recording window (record the actual server, not a shell wrapper that spawns it).","Run py-spy with sudo/Administrator for the entire recording so child process metadata stays readable.","Retry the recording; transient target exit mid-session is the most common cause.","Record a specific child pid without --subprocesses if the tree churns constantly."],"exampleFix":"// before: recording a shell wrapper that exits when children die\npy-spy record --subprocesses -o p.svg -- ./run_workers.sh\n// after: record the long-lived parent directly\nWORKER_PID=$(pgrep -f worker.py | head -1)\nsudo py-spy record --subprocesses -o p.svg --pid $WORKER_PID --duration 60","handlingStrategy":"retry","validationCode":"# ensure parent stays alive and we can read its children\nkill -0 \"$PID\" 2>/dev/null || { echo \"target exited\" >&2; exit 1; }\nls /proc/$PID/task >/dev/null 2>&1 || { echo 'no permission on /proc target'; exit 1; }","typeGuard":null,"tryCatchPattern":"for i in 1 2 3; do\n  sudo py-spy record --pid \"$PID\" --subprocesses -o p.svg --duration 60 && break\n  pgrep -f worker.py >/dev/null || break   # don't retry if target tree is gone\n  sleep 2\ndone","preventionTips":["Record a long-lived parent (server process), not shell wrappers that exit with their children.","Hold root/Administrator privileges for the full recording duration.","Re-check the target is alive before retrying failed recordings."],"tags":["process-enumeration","subprocesses","sampling","race-condition"],"backgroundTag":"process-enumeration-failed","analyzedSha":"32080cc0c22bc23938541dfa7dabb6090e40be14","analyzedAt":"2026-09-05T19:30:55.142Z","contentChangedAt":"2026-09-05T19:30:55.142Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}