domains / / cline/CLINE
Safe Startup Error Handling
For startup/OS-specific code paths, handle failures predictably: don’t panic on edge cases; when recovery is possible, retry with backoff; when you must fail, surface bounded, non-sensitive diagnostics.
For startup/OS-specific code paths, handle failures predictably: don’t panic on edge cases; when recovery is possible, retry with backoff; when you must fail, surface bounded, non-sensitive diagnostics.
Apply this standard: 1) Avoid panics on invalid inputs
- Validate invariants (e.g., non-empty work areas, valid coordinate ranges) before clamping/transforming.
- If the invariant can’t be satisfied, return an error and keep the app running (or fall back to a safe behavior) rather than crashing.
2) Provide bounded, sanitized failure context
- Any logs/diagnostics captured during startup must be:
- bounded in count/size to prevent memory blowups
- sanitized to avoid leaking secrets/tokens
- Include exit status and a short diagnostic summary in the final error message.
3) Prefer graceful recovery over immediate failure
- For readiness/endpoint publication, use a wait loop with a deadline.
- If the process dies before publishing, respawn (paced with backoff) rather than failing the whole flow.
- In process lifecycle code, treat “already exited” teardown cases as non-fatal.
Illustrative pattern (Rust-like pseudocode):
const MAX_LINES: usize = 32;
const MAX_LINE_LEN: usize = 1024;
fn sanitize_diagnostic(line: &str) -> String {
// redact/omit known sensitive markers; keep output bounded
let trimmed: String = line.chars().filter(|c| !c.is_control()).take(MAX_LINE_LEN).collect();
if trimmed.to_lowercase().contains("token") {
"[Sensitive startup diagnostic omitted]".to_string()
} else {
trimmed
}
}
fn record_startup_failure(diags: &mut VecDeque<String>, line: &str) {
if diags.len() == MAX_LINES { diags.pop_front(); }
let line = sanitize_diagnostic(line);
if !line.is_empty() { diags.push_back(line); }
}
fn ensure_ready_or_recover(wait_deadline: Instant, mut respawn: impl FnMut() -> Result<(), String>) -> Result<String, String> {
while Instant::now() < wait_deadline {
// check readiness...
// if child exited early: respawn with backoff
// continue waiting...
}
// return an error that includes bounded diagnostics + exit info
Err("Startup failed: endpoint not published within timeout".to_string())
}
Result: users get a graceful failure (or recovery), developers get actionable context, and the app avoids catastrophic crashes from edge-case OS/input conditions.