Skip to content

Commit 74e633f

Browse files
fix(session): surface sidecar crash errors to frontend
When a sidecar (node/codex) crashes immediately (e.g. due to shared library mismatches), stderr output is now collected and emitted as a SessionError event so the UI can display a meaningful error message instead of silently failing.
1 parent ffc20d3 commit 74e633f

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

crates/session/src/claude.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,20 +161,32 @@ impl ClaudeSession {
161161
let stdin = child.stdin.take().context("Failed to capture stdin")?;
162162
let stderr = child.stderr.take();
163163

164-
// Stderr reader — log sidecar errors
164+
let (event_tx, event_rx) = mpsc::unbounded_channel();
165+
166+
// Stderr reader — collect stderr and emit a SessionError if the sidecar
167+
// crashes before producing any stdout (e.g. shared-library mismatch).
165168
if let Some(stderr) = stderr {
169+
let err_tx = event_tx.clone();
166170
tokio::spawn(async move {
167171
let reader = BufReader::new(stderr);
168172
let mut lines = reader.lines();
173+
let mut stderr_lines = Vec::new();
169174
while let Ok(Some(line)) = lines.next_line().await {
170175
if !line.trim().is_empty() {
171176
tracing::warn!("sidecar stderr: {line}");
177+
stderr_lines.push(line);
172178
}
173179
}
180+
// If the sidecar wrote to stderr and then exited, surface it.
181+
if !stderr_lines.is_empty() {
182+
let message = format!(
183+
"Agent sidecar crashed: {}",
184+
stderr_lines.join("; ")
185+
);
186+
let _ = err_tx.send(AgentEvent::SessionError { message });
187+
}
174188
});
175189
}
176-
177-
let (event_tx, event_rx) = mpsc::unbounded_channel();
178190
let (stdin_tx, mut stdin_rx) = mpsc::unbounded_channel::<String>();
179191
let claude_session_id: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
180192

crates/session/src/codex.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,25 @@ impl CodexSession {
9393
}
9494
});
9595

96-
// Stderr reader task.
96+
// Stderr reader task — surface crash diagnostics.
97+
let err_tx = event_tx.clone();
9798
tokio::spawn(async move {
9899
let reader = BufReader::new(stderr);
99100
let mut lines = reader.lines();
101+
let mut stderr_lines = Vec::new();
100102
while let Ok(Some(line)) = lines.next_line().await {
101103
if !line.trim().is_empty() {
102104
warn!("codex stderr: {line}");
105+
stderr_lines.push(line);
103106
}
104107
}
108+
if !stderr_lines.is_empty() {
109+
let message = format!(
110+
"Codex process crashed: {}",
111+
stderr_lines.join("; ")
112+
);
113+
let _ = err_tx.send(AgentEvent::SessionError { message });
114+
}
105115
});
106116

107117
// Stdout NDJSON reader task.

0 commit comments

Comments
 (0)