Hmbown/CodeWhale · critical · anyhow::Error
timed out waiting for runtime API bridge at {}/health
Error message
timed out waiting for runtime API bridge at {}/health What it means
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.
Source
Thrown at crates/app-server/src/lib.rs:1085
let deadline = Instant::now() + Duration::from_secs(15);
loop {
if let Some(child) = self.child.as_mut()
&& let Some(status) = child.try_wait()?
{
return Err(anyhow!(
"runtime API bridge exited before becoming ready (status {status})"
));
}
match self
.client
.get(format!("{}/health", self.base_url))
.send()
.await
{
Ok(response) if response.status().is_success() => return Ok(()),
_ if Instant::now() >= deadline => {
bail!(
"timed out waiting for runtime API bridge at {}/health",
self.base_url
)
}
_ => tokio::time::sleep(Duration::from_millis(50)).await,
}
}
}
fn authed(&self, builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
match self.auth_token.as_deref() {
Some(token) => builder.bearer_auth(token),
None => builder,
}
}
async fn request_json(&self, builder: reqwest::RequestBuilder) -> Result<Value> {
let response = builder.send().await?;View on GitHub (pinned to 0c42157ee5)
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
Defensive patterns
Strategy: retry
Validate before calling
// Before trusting a plugin path, recompute its content hash and compare with the reviewed digest:
fn plugin_matches_review(path: &std::path::Path, expected_sha256: &str) -> bool {
// sha256 over the file bytes, hex-encode, constant-time compare with expected_sha256
true
} Try / catch
match open_bundle_identity_probe(&path, expect_dir) {
Err(e) if e.to_string().contains("identity probe") => {
// do NOT use the plugin; trigger re-review / reinstall, then retry
}
other => other,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Cloud sync rewriting files inside the plugins directory; users editing staged plugin files by hand; hostile content trying to pivot after passing review.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- refusing non-loopback app-server bind without explicit auth
- refusing unauthenticated app-server bind on non-loopback add
- app-server auth token cannot be empty
- No session selected.
- SHA256 mismatch for {} from {}! expected: {expected} act
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/23e266d6b45bc388.
Report an issue: GitHub.