Hmbown/CodeWhale · error
workspace .env FIFO blocked startup
Error message
workspace .env FIFO blocked startup: {timeout} What it means
A test-timeout panic inside a workspace .env loading test. The test creates a FIFO (named pipe) where a real .env file would be, starts the loader in a worker thread, and expects the loader to fail fast with 'not a regular file'. If the loader instead blocks on reading the FIFO, the receiver times out after 1 second and the test panics with 'workspace .env FIFO blocked startup: {timeout}', which also opens a writer to unblock and join the worker.
Solutions
- Restore an explicit regular-file validation (fs::metadata + is_file) in the workspace .env loader before opening the file.
- Ensure the loader rejects non-regular files with an error containing 'not a regular file' rather than attempting to read.
- If the failure is a flaky timeout on slow machines, raise the recv_timeout budget or the Duration used in the panic message.
- Re-run the single test to confirm the loader now fails fast on FIFOs.
Example fix
// before
let contents = std::fs::read_to_string(&dotenv)?;
// after
let meta = std::fs::metadata(&dotenv)?;
if !meta.is_file() {
return Err(anyhow!("workspace .env is not a regular file"));
}
let contents = std::fs::read_to_string(&dotenv)?; Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::metadata(&dotenv_path).ok()?;
if !meta.is_file() {
return Err("workspace .env is not a regular file");
} Type guard
fn is_regular_file(p: &std::path::Path) -> bool {
std::fs::metadata(p).map(|m| m.is_file()).unwrap_or(false)
} Try / catch
match std::fs::metadata(&dotenv) {
Ok(m) if m.is_file() => load_dotenv(&dotenv),
_ => return Err(anyhow!("workspace .env is not a regular file")),
} Prevention
- Always stat the .env path before opening it; never stream-read blindly
- Reject FIFOs, devices, and sockets at startup with a clear error
- Keep loader startup non-blocking; bound any read with a timeout
- Test with special files (FIFO/dev) in CI to catch regressions
When it happens
Trigger: The .env loader blocks reading a FIFO instead of rejecting it; rx.recv_timeout(1s) elapses without the expected error being sent, hitting the panic in the timeout arm.
Common situations: A developer replaces the regular-file check (metadata().is_file()) with a streaming read; a regression lets startup hang on a FIFO or device file placed at the workspace .env path; slow CI makes the 1-second timeout too tight.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- child wall-time budget exhausted
- Expected Ok, got
- expected resume command
- Expected Warning for relative path argument, got
- first timed-out API attempt should reach the test server
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/2ceb0d0b91b90db1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lib.rs:17682
let worker = std::thread::spawn(move || {
let result = load_workspace_dotenv_credentials_from_path(&worker_path)
.map(|_| "unexpected success".to_string())
.unwrap_or_else(|error| error.to_string());
tx.send(result).expect("send loader result");
});
let error = match rx.recv_timeout(Duration::from_secs(1)) {
Ok(error) => error,
Err(timeout) => {
// Release a regressed blocking reader so the test can fail
// promptly instead of leaving a stuck process behind.
let _writer = std::fs::OpenOptions::new()
.write(true)
.open(&dotenv)
.expect("open fifo writer to release blocked reader");
let _ = rx.recv_timeout(Duration::from_secs(1));
worker.join().expect("join released loader");
panic!("workspace .env FIFO blocked startup: {timeout}");
}
};
worker.join().expect("join loader");
assert!(error.contains("not a regular file"), "{error}");
}
#[test]
fn exec_json_conflicts_with_stream_json_output() {
let err = Cli::try_parse_from([
"codewhale",
"exec",
"--json",
"--output-format",
"stream-json",
"hello",
])
.expect_err("json summary and stream-json must not mix");View on GitHub (pinned to 433685b202)