{"record":{"id":"9a32f0e2a41dadae","repo":"neondatabase/neon","slug":"pg-ctl-status-returned-no-status-code","errorCode":null,"errorMessage":"pg_ctl status returned no status code","messagePattern":"pg_ctl status returned no status code","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"control_plane/src/storage_controller.rs","lineNumber":774,"sourceCode":"        let pg_data_path = self.env.base_data_dir.join(\"storage_controller_db\");\n\n        let pg_status_args = [\"-D\", &pg_data_path.to_string_lossy(), \"status\"];\n        let status_exitcode = self.pg_ctl(pg_status_args).await;\n\n        // pg_ctl status returns this exit code if postgres is not running: in this case it is\n        // fine that stop failed.  Otherwise it is an error that stop failed.\n        const PG_STATUS_NOT_RUNNING: i32 = 3;\n        const PG_NO_DATA_DIR: i32 = 4;\n        const PG_STATUS_RUNNING: i32 = 0;\n        match status_exitcode.code() {\n            Some(PG_STATUS_NOT_RUNNING) => Ok(false),\n            Some(PG_NO_DATA_DIR) => Ok(false),\n            Some(PG_STATUS_RUNNING) => Ok(true),\n            Some(code) => Err(anyhow::anyhow!(\n                \"pg_ctl status returned unexpected status code: {:?}\",\n                code\n            )),\n            None => Err(anyhow::anyhow!(\"pg_ctl status returned no status code\")),\n        }\n    }\n\n    fn get_claims_for_path(path: &str) -> anyhow::Result<Option<Claims>> {\n        let category = match path.find('/') {\n            Some(idx) => &path[..idx],\n            None => path,\n        };\n\n        match category {\n            \"status\" | \"ready\" => Ok(None),\n            \"control\" | \"debug\" => Ok(Some(Claims::new(None, Scope::Admin))),\n            \"v1\" => Ok(Some(Claims::new(None, Scope::PageServerApi))),\n            _ => Err(anyhow::anyhow!(\"Failed to determine claims for {}\", path)),\n        }\n    }\n\n    /// Simple HTTP request wrapper for calling into storage controller","sourceCodeStart":756,"sourceCodeEnd":792,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/control_plane/src/storage_controller.rs#L756-L792","documentation":"The status check asks for pg_ctl's exit code and gets none (ExitStatus::code() returns None), which happens only when the process was terminated by a signal rather than exiting normally.","triggerScenarios":"pg_ctl is killed by a signal while running status — OOM killer, manual kill -9, or a test environment reaping process trees.","commonSituations":"Memory-pressured CI machines OOM-killing helper processes, parallel test teardown killing whole process groups.","solutions":["Check kernel logs (dmesg) for an OOM kill of pg_ctl and free memory","Remove whatever sends the signal (kill scripts, reapers) and retry the stop/status operation"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match status.code() {\n    Some(code) => classify(code),\n    None => {\n        // pg_ctl was signalled; fall back to postmaster.pid liveness\n        check_postmaster_pid_alive(&pg_data_path)\n    }\n}","preventionTips":["Watch memory usage on CI hosts to avoid OOM kills of pg_ctl","Avoid kill -9 on process trees that include pg_ctl","Fall back to postmaster.pid checks when exit codes are unavailable"],"tags":["rust","storage-controller","postgres","pg-ctl","signal"],"backgroundTag":"process-killed-by-signal","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}