{"record":{"id":"c62837761b619847","repo":"linera-io/linera-protocol","slug":"failed-to-start-child-server","errorCode":null,"errorMessage":"Failed to start child server","messagePattern":"Failed to start child server","errorType":"exception","errorClass":"anyhow","httpStatus":null,"severity":"error","filePath":"linera-storage-service/src/child.rs","lineNumber":49,"sourceCode":"    }\n\n    fn command(&self) -> Command {\n        let mut command = Command::new(&self.binary);\n        command.args([\"memory\", \"--endpoint\", &self.endpoint]);\n        command.kill_on_drop(true);\n        command\n    }\n\n    /// Waits for the absence of the endpoint. If a child is terminated\n    /// then it might take time to wait for its absence.\n    async fn wait_for_absence(&self) -> Result<()> {\n        for i in 1..10 {\n            if storage_service_check_absence(&self.endpoint).await? {\n                return Ok(());\n            }\n            linera_base::time::timer::sleep(Duration::from_secs(i)).await;\n        }\n        bail!(\"Failed to start child server\");\n    }\n\n    /// Starts the storage service child process and returns a guard that keeps it alive.\n    pub async fn run(&self) -> Result<StorageServiceGuard> {\n        self.wait_for_absence().await?;\n        let mut command = self.command();\n        let child = command.spawn_into()?;\n        let guard = StorageServiceGuard { _child: child };\n        // We iterate until the child is spawned and can be accessed.\n        // We add an additional waiting period to avoid problems.\n        for i in 1..10 {\n            let result = storage_service_check_validity(&self.endpoint).await;\n            if result.is_ok() {\n                return Ok(guard);\n            }\n            linera_base::time::timer::sleep(Duration::from_secs(i)).await;\n        }\n        bail!(\"Failed to start child server\");","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-storage-service/src/child.rs#L31-L67","documentation":"Raised by `StorageService::wait_for_absence` (linera-storage-service child.rs) before spawning a child storage service. It polls `storage_service_check_absence` for the configured endpoint with increasing sleeps (1+2+...+9 ≈ 45s); if something is still serving on that endpoint after all attempts, it bails. In practice the endpoint is occupied by a leftover storage-service process (or previous child) that never shut down.","triggerScenarios":"Calling `StorageService::run` on an endpoint where another storage service (from a previous test run, a crashed guard, or an orphaned process) is still listening and answering presence checks.","commonSituations":"Back-to-back e2e tests reusing the same endpoint without killing the previous service; a leaked child from a test that panicked before dropping its guard; a stale process from an aborted cargo test run.","solutions":["Find and kill the process holding the endpoint (e.g. `lsof -i :7878` / `ss -ltnp` then kill, or `pkill -f linera-storage-service`)","Use a unique endpoint/port per test run so services never collide","If the previous child is legitimately still shutting down, allow more time or retry the run","Make sure StorageServiceGuard values are dropped (or the test aborts cleanly) so children are killed between tests"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Rust: verify the endpoint is free before StorageService::run\nuse tokio::net::TcpStream;\n\nasync fn endpoint_free(host: &str, port: u16) -> bool {\n    TcpStream::connect((host, port)).await.is_err() // connectable => something is serving\n}\n\nif !endpoint_free(\"127.0.0.1\", port).await {\n    anyhow::bail!(\"endpoint {port} is occupied; kill the old storage service first\");\n}","typeGuard":null,"tryCatchPattern":"match storage_service.run().await {\n    Ok(guard) => guard,\n    Err(e) if e.to_string().contains(\"Failed to start child server\") => {\n        // endpoint still occupied: kill the stale process, then retry once\n        let _ = std::process::Command::new(\"pkill\")\n            .args([\"-f\", \"linera-storage-service\"])\n            .status();\n        storage_service.run().await?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Allocate a unique endpoint/port per test (e.g. from a port counter or ephemeral range)","Ensure StorageServiceGuard is dropped at test end so the child is killed (kill_on_drop is set)","Sweep for orphaned storage-service processes before a test suite starts"],"tags":["storage-service","port-conflict","startup","testing"],"backgroundTag":"port-already-in-use","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}