{"record":{"id":"23e266d6b45bc388","repo":"Hmbown/CodeWhale","slug":"timed-out-waiting-for-runtime-api-bridge-at-hea","errorCode":null,"errorMessage":"timed out waiting for runtime API bridge at {}/health","messagePattern":"timed out waiting for runtime API bridge at (.+?)/health","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/app-server/src/lib.rs","lineNumber":1085,"sourceCode":"        let deadline = Instant::now() + Duration::from_secs(15);\n        loop {\n            if let Some(child) = self.child.as_mut()\n                && let Some(status) = child.try_wait()?\n            {\n                return Err(anyhow!(\n                    \"runtime API bridge exited before becoming ready (status {status})\"\n                ));\n            }\n\n            match self\n                .client\n                .get(format!(\"{}/health\", self.base_url))\n                .send()\n                .await\n            {\n                Ok(response) if response.status().is_success() => return Ok(()),\n                _ if Instant::now() >= deadline => {\n                    bail!(\n                        \"timed out waiting for runtime API bridge at {}/health\",\n                        self.base_url\n                    )\n                }\n                _ => tokio::time::sleep(Duration::from_millis(50)).await,\n            }\n        }\n    }\n\n    fn authed(&self, builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {\n        match self.auth_token.as_deref() {\n            Some(token) => builder.bearer_auth(token),\n            None => builder,\n        }\n    }\n\n    async fn request_json(&self, builder: reqwest::RequestBuilder) -> Result<Value> {\n        let response = builder.send().await?;","sourceCodeStart":1067,"sourceCodeEnd":1103,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/app-server/src/lib.rs#L1067-L1103","documentation":"After review, Codewhale reopens plugin paths with a zero-access probe (open_bundle_identity_probe) to compare handle identity against the retained authority handle. The probe again requires the expected kind (file with exactly one link, or directory) and no reparse attribute. InvalidData here means the path no longer resolves to the reviewed object: it was replaced, gained a hard link, or became a reparse point between review and use.","triggerScenarios":"A plugin file or directory is swapped after passing review (TOCTOU), given a second hard link, or replaced by a junction; tools that 'restore' files by delete-and-recreate (cloud sync clients, AV quarantine) also trigger it.","commonSituations":"Cloud sync rewriting files inside the plugins directory; users editing staged plugin files by hand; hostile content trying to pivot after passing review.","solutions":["Re-run plugin review (or reinstall the plugin) so the new content is hashed and trusted","Exclude the plugins directory from sync and AV software that rewrite files in place","If you did not change the file yourself, treat it as a security event and investigate what did"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before trusting a plugin path, recompute its content hash and compare with the reviewed digest:\nfn plugin_matches_review(path: &std::path::Path, expected_sha256: &str) -> bool {\n    // sha256 over the file bytes, hex-encode, constant-time compare with expected_sha256\n    true\n}","typeGuard":null,"tryCatchPattern":"match open_bundle_identity_probe(&path, expect_dir) {\n    Err(e) if e.to_string().contains(\"identity probe\") => {\n        // do NOT use the plugin; trigger re-review / reinstall, then retry\n    }\n    other => other,\n}","preventionTips":["Exclude plugin directories from sync and AV tools that rewrite files in place","Never edit staged plugin files manually; reinstall via the review flow","Treat repeated probe failures as tampering and investigate"],"tags":["plugins","windows","toctou","integrity","invalid-data"],"backgroundTag":"toctou-file-swap","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}