{"record":{"id":"1fbd997496e2fbff","repo":"affaan-m/ECC","slug":"spawned-process-did-not-expose-a-process-id","errorCode":null,"errorMessage":"Spawned process did not expose a process id","messagePattern":"Spawned process did not expose a process id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/session/runtime.rs","lineNumber":172,"sourceCode":"            Some(stdout) => stdout,\n            None => {\n                let _ = child.kill().await;\n                let _ = child.wait().await;\n                anyhow::bail!(\"Child stdout was not piped\");\n            }\n        };\n        let stderr = match child.stderr.take() {\n            Some(stderr) => stderr,\n            None => {\n                let _ = child.kill().await;\n                let _ = child.wait().await;\n                anyhow::bail!(\"Child stderr was not piped\");\n            }\n        };\n\n        let pid = child\n            .id()\n            .ok_or_else(|| anyhow::anyhow!(\"Spawned process did not expose a process id\"))?;\n        db_writer.update_pid(Some(pid)).await?;\n        db_writer.update_state(SessionState::Running).await?;\n        db_writer.touch_heartbeat().await?;\n\n        let heartbeat_writer = db_writer.clone();\n        let heartbeat_task = tokio::spawn(async move {\n            let mut ticker = time::interval(heartbeat_interval);\n            ticker.set_missed_tick_behavior(MissedTickBehavior::Delay);\n            loop {\n                ticker.tick().await;\n                if heartbeat_writer.touch_heartbeat().await.is_err() {\n                    break;\n                }\n            }\n        });\n\n        let stdout_task = tokio::spawn(capture_stream(\n            session_id.clone(),","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/session/runtime.rs#L154-L190","documentation":"capture_command_output spawns the session command and immediately needs its pid to record via db_writer.update_pid. child.id() returning None (process already reaped or platform pid exposure failure) aborts capture with this error, since heartbeat/stop tracking is pid-based.","triggerScenarios":"The spawned command exits instantly (bad args, missing interpreter) so the Child has no id; or a platform-level spawn quirk (Windows) prevents pid exposure right after a successful spawn().","commonSituations":"Command string referencing a nonexistent binary wrapped by a shell that exits immediately; stdin/stderr piping misconfiguration causing early exit; race with very short-lived processes.","solutions":["Verify the command runs standalone before scheduling it in a session","Capture and report child.try_wait() status alongside the missing pid to reveal the instant exit","Retry the spawn; if pid tracking is optional, degrade gracefully instead of failing the whole capture"],"exampleFix":"// before\nlet pid = child.id().ok_or_else(|| anyhow::anyhow!(\"Spawned process did not expose a process id\"))?;\n// after\nlet pid = child.id().with_context(|| format!(\"spawned process exited immediately: {:?}\", child.try_wait()))?;","handlingStrategy":"try-catch","validationCode":"// dry-run the command first\nlet ok = Command::new(\"sh\").arg(\"-c\").arg(\"command -v <cmd>\").status().map(|s| s.success()).unwrap_or(false);\nassert!(ok, \"command not runnable\");","typeGuard":null,"tryCatchPattern":"match capture_command_output(...).await {\n    Err(e) if e.to_string().contains(\"did not expose a process id\") => {\n        eprintln!(\"process exited before pid capture; inspect command args and output\");\n    }\n    Err(e) => return Err(e),\n    Ok(v) => v,\n}","preventionTips":["Validate command strings/args before scheduling sessions","Handle instantly-exiting commands (bad binaries, bad env)","Report try_wait() status when pid capture fails for better diagnostics"],"tags":["rust","process","spawn","pid","tokio"],"backgroundTag":"process-pid-unavailable","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}