Skip to content

Commit 7b4aacb

Browse files
committed
fix: improve error formatting for streaming responses
- Handle Value::Error in ListStream and single value responses - Extract ShellError from ByteStream io::Error via ShellErrorBridge - Propagate original errors in to sse instead of "expected record" - Use log_error instead of eprintln for consistent error output Streaming errors now show full nushell error context with source spans instead of short messages like "Type mismatch."
1 parent 948e4c0 commit 7b4aacb

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

src/commands.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ fn event_to_string(config: &Config, val: Value) -> Result<String, ShellError> {
410410
let span = val.span();
411411
let rec = match val {
412412
Value::Record { val, .. } => val,
413+
// Propagate the original error instead of creating a new "expected record" error
414+
Value::Error { error, .. } => return Err(*error),
413415
other => {
414416
return Err(ShellError::TypeMismatch {
415417
err_message: format!("expected record, got {}", other.get_type()),

src/worker.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use crate::commands::RESPONSE_TX;
2+
use crate::logging::log_error;
23
use crate::request::{request_to_value, Request};
34
use crate::response::{value_to_bytes, Response, ResponseBodyType, ResponseTransport};
45
use nu_protocol::{
5-
engine::{Job, ThreadJob},
6-
PipelineData, Value,
6+
engine::{Job, StateWorkingSet, ThreadJob},
7+
format_cli_error, PipelineData, Value,
78
};
89
use std::io::Read;
910
use std::sync::{mpsc, Arc};
@@ -65,6 +66,10 @@ pub fn spawn_eval_thread(
6566
let _ = body_tx.send((inferred_content_type, ResponseTransport::Empty));
6667
Ok(())
6768
}
69+
PipelineData::Value(Value::Error { error, .. }, _) => {
70+
let working_set = StateWorkingSet::new(&engine.state);
71+
Err(format_cli_error(&working_set, error.as_ref(), None).into())
72+
}
6873
PipelineData::Value(value, _) => {
6974
let _ = body_tx.send((
7075
inferred_content_type,
@@ -76,6 +81,12 @@ pub fn spawn_eval_thread(
7681
let (stream_tx, stream_rx) = tokio_mpsc::channel(32);
7782
let _ = body_tx.send((inferred_content_type, ResponseTransport::Stream(stream_rx)));
7883
for value in stream.into_inner() {
84+
// Check for errors in the stream and log them properly
85+
if let Value::Error { error, .. } = &value {
86+
let working_set = StateWorkingSet::new(&engine.state);
87+
log_error(&format_cli_error(&working_set, error.as_ref(), None));
88+
break;
89+
}
7990
if stream_tx.blocking_send(value_to_bytes(value)).is_err() {
8091
break;
8192
}
@@ -100,7 +111,19 @@ pub fn spawn_eval_thread(
100111
break;
101112
}
102113
}
103-
Err(err) => return Err(err.into()),
114+
Err(err) => {
115+
// Try to extract ShellError from the io::Error for proper formatting
116+
use nu_protocol::shell_error::bridge::ShellErrorBridge;
117+
if let Some(bridge) = err
118+
.get_ref()
119+
.and_then(|e| e.downcast_ref::<ShellErrorBridge>())
120+
{
121+
let working_set = StateWorkingSet::new(&engine.state);
122+
log_error(&format_cli_error(&working_set, &bridge.0, None));
123+
break; // Error already logged, just stop streaming
124+
}
125+
return Err(err.into());
126+
}
104127
}
105128
}
106129
Ok(())
@@ -148,7 +171,7 @@ pub fn spawn_eval_thread(
148171
};
149172

150173
if let Some(err) = err_msg {
151-
eprintln!("Error in eval thread: {err}");
174+
log_error(&err);
152175
if let (Some(meta_tx), Some(body_tx)) = (meta_tx_opt.take(), body_tx_opt.take()) {
153176
let _ = meta_tx.send(Response {
154177
status: 500,

0 commit comments

Comments
 (0)