diff --git a/rust/src/parser/src/tool/deepseek_json/deepseek_v3.rs b/rust/src/parser/src/tool/deepseek_json/deepseek_v3.rs
index ea1a660cce..dc9859d001 100644
--- a/rust/src/parser/src/tool/deepseek_json/deepseek_v3.rs
+++ b/rust/src/parser/src/tool/deepseek_json/deepseek_v3.rs
@@ -238,6 +238,9 @@ mod tests {
let error = parser.parse_chunk(&input).unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[
+ r#"tool parser parsing failed: near "tool<|tool▁sep|>get_weather\n```json\n{}": "#
+ ]]
+ .assert_eq(&error.to_report_string());
}
}
diff --git a/rust/src/parser/src/tool/deepseek_json/deepseek_v31.rs b/rust/src/parser/src/tool/deepseek_json/deepseek_v31.rs
index cf2ea19628..088e6d53db 100644
--- a/rust/src/parser/src/tool/deepseek_json/deepseek_v31.rs
+++ b/rust/src/parser/src/tool/deepseek_json/deepseek_v31.rs
@@ -242,6 +242,7 @@ mod tests {
let error = parser.parse_chunk(&input).unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[r#"tool parser parsing failed: near "<|tool▁sep|>{}": "#]]
+ .assert_eq(&error.to_report_string());
}
}
diff --git a/rust/src/parser/src/tool/json/granite4.rs b/rust/src/parser/src/tool/json/granite4.rs
index 4989578011..0f7bb69021 100644
--- a/rust/src/parser/src/tool/json/granite4.rs
+++ b/rust/src/parser/src/tool/json/granite4.rs
@@ -540,8 +540,10 @@ mod tests {
.parse_chunk(r#"{"name":"f","arguments":42}"#)
.unwrap_err();
- expect!["tool parser parsing failed: invalid Granite4 arguments"]
- .assert_eq(&error.to_report_string());
+ expect![[
+ r#"tool parser parsing failed: near "42}": invalid Granite4 arguments"#
+ ]]
+ .assert_eq(&error.to_report_string());
}
#[test]
diff --git a/rust/src/parser/src/tool/json/internlm2.rs b/rust/src/parser/src/tool/json/internlm2.rs
index aae3b9f6a0..25bc65911a 100644
--- a/rust/src/parser/src/tool/json/internlm2.rs
+++ b/rust/src/parser/src/tool/json/internlm2.rs
@@ -335,7 +335,7 @@ mod tests {
let error = parser.parse_chunk(&input).unwrap_err();
expect![[r#"
- tool parser parsing failed: invalid InternLM2
+ tool parser parsing failed: near "{\"name\":\"get_weather\",\"params\":{\"location\":\"Tokyo\"}}<|action_end|>": invalid InternLM2
expected `parameters`, `arguments`"#]]
.assert_eq(&error.to_report_string());
}
diff --git a/rust/src/parser/src/tool/json/llama.rs b/rust/src/parser/src/tool/json/llama.rs
index b736f27e30..9f30bbe84a 100644
--- a/rust/src/parser/src/tool/json/llama.rs
+++ b/rust/src/parser/src/tool/json/llama.rs
@@ -336,7 +336,7 @@ mod tests {
.unwrap_err();
expect![[r#"
- tool parser parsing failed: invalid Llama JSON
+ tool parser parsing failed: near "{\"name\":\"get_weather\",\"arguments\":{\"location\":\"Tokyo\"}}": invalid Llama JSON
expected `parameters`"#]]
.assert_eq(&error.to_report_string());
}
@@ -474,7 +474,7 @@ mod tests {
let error = parser.parse_chunk(r#"{"parameters":{},"name":"get_weather"}"#).unwrap_err();
expect![[r#"
- tool parser parsing failed: invalid Llama JSON
+ tool parser parsing failed: near "{\"parameters\":{},\"name\":\"get_weather\"}": invalid Llama JSON
expected `name`"#]]
.assert_eq(&error.to_report_string());
}
@@ -489,7 +489,7 @@ mod tests {
))
.unwrap_err();
- expect!["tool parser parsing failed: invalid Llama JSON"]
+ expect![[r#"tool parser parsing failed: near " trailing": invalid Llama JSON"#]]
.assert_eq(&error.to_report_string());
}
}
diff --git a/rust/src/parser/src/tool/json/mistral.rs b/rust/src/parser/src/tool/json/mistral.rs
index 8a20b4db7b..ab99afc7ef 100644
--- a/rust/src/parser/src/tool/json/mistral.rs
+++ b/rust/src/parser/src/tool/json/mistral.rs
@@ -240,7 +240,7 @@ mod tests {
.unwrap_err();
expect![[r#"
- tool parser parsing failed: invalid Mistral
+ tool parser parsing failed: near "{\"arguments\":{},\"name\":\"get_weather\"}]": invalid Mistral
expected `name`"#]]
.assert_eq(&error.to_report_string());
}
diff --git a/rust/src/parser/src/tool/json/qwen.rs b/rust/src/parser/src/tool/json/qwen.rs
index 7fa53c9007..a69798f785 100644
--- a/rust/src/parser/src/tool/json/qwen.rs
+++ b/rust/src/parser/src/tool/json/qwen.rs
@@ -280,7 +280,7 @@ mod tests {
.unwrap_err();
expect![[r#"
- tool parser parsing failed: invalid Qwen XML
+ tool parser parsing failed: near "{\"arguments\":{},\"name\":\"get_weather\"}\n": invalid Qwen XML
expected `name`"#]]
.assert_eq(&error.to_report_string());
}
diff --git a/rust/src/parser/src/tool/kimi_k2.rs b/rust/src/parser/src/tool/kimi_k2.rs
index b692c1ec59..e4730f96bc 100644
--- a/rust/src/parser/src/tool/kimi_k2.rs
+++ b/rust/src/parser/src/tool/kimi_k2.rs
@@ -594,6 +594,9 @@ mod tests {
let error = parser.parse_chunk(&input).unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[
+ r#"tool parser parsing failed: near "get_weather<|tool_call_argument_begin|>{}": "#
+ ]]
+ .assert_eq(&error.to_report_string());
}
}
diff --git a/rust/src/parser/src/tool/minimax_m2.rs b/rust/src/parser/src/tool/minimax_m2.rs
index 5c5411775a..c56b4bd1f6 100644
--- a/rust/src/parser/src/tool/minimax_m2.rs
+++ b/rust/src/parser/src/tool/minimax_m2.rs
@@ -593,6 +593,7 @@ mod tests {
let mut parser = MinimaxM2ToolParser::new(&test_tools());
let error = parser.parse_chunk("").unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[r#"tool parser parsing failed: near "": "#]]
+ .assert_eq(&error.to_report_string());
}
}
diff --git a/rust/src/parser/src/tool/minimax_m3.rs b/rust/src/parser/src/tool/minimax_m3.rs
index a1ab375b73..e2a0cada2c 100644
--- a/rust/src/parser/src/tool/minimax_m3.rs
+++ b/rust/src/parser/src/tool/minimax_m3.rs
@@ -878,7 +878,10 @@ mod tests {
))
.unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[
+ r#"tool parser parsing failed: near "]<]minimax[>[]<]minimax[>[": "#
+ ]]
+ .assert_eq(&error.to_report_string());
}
#[test]
diff --git a/rust/src/parser/src/tool/qwen_coder.rs b/rust/src/parser/src/tool/qwen_coder.rs
index d67a5c42f1..c2e1b0c794 100644
--- a/rust/src/parser/src/tool/qwen_coder.rs
+++ b/rust/src/parser/src/tool/qwen_coder.rs
@@ -685,7 +685,8 @@ mod tests {
let mut parser = Qwen3CoderToolParser::new(&test_tools());
let error = parser.parse_chunk("\n\n").unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[r#"tool parser parsing failed: near "\n\n": "#]]
+ .assert_eq(&error.to_report_string());
}
#[test]
@@ -697,7 +698,7 @@ mod tests {
)
.unwrap_err();
- expect!["tool parser parsing failed: "].assert_eq(&error.to_report_string());
+ expect![[r#"tool parser parsing failed: near "\n\nSF\n": "#]].assert_eq(&error.to_report_string());
}
#[test]
diff --git a/rust/src/parser/src/utils.rs b/rust/src/parser/src/utils.rs
index bd8f6f48e9..c692a57c88 100644
--- a/rust/src/parser/src/utils.rs
+++ b/rust/src/parser/src/utils.rs
@@ -395,9 +395,9 @@ pub fn parse_buffered_event(
Ok(event) => event,
Err(ErrMode::Incomplete(_)) => return Ok(None),
Err(ErrMode::Backtrack(e) | ErrMode::Cut(e)) => {
- // TODO: enrich context for error reporting
+ let snippet = buffer.char_indices().nth(80).map_or(buffer, |(i, _)| &buffer[..i]);
return Err(ToolParserError::ParsingFailed {
- message: e.to_string(),
+ message: format!("near {snippet:?}: {e}"),
});
}
};
@@ -423,8 +423,9 @@ mod tests {
use winnow::stream::{Offset, Partial, Stream};
use super::{
- JsonObjectScanState, JsonStringScanState, MarkerScanState, json_str, partial_prefix_len,
- safe_text_len, safe_text_len_mul, take_json_object, take_json_string, take_until_marker,
+ JsonObjectScanState, JsonStringScanState, MarkerScanState, json_str, parse_buffered_event,
+ partial_prefix_len, safe_text_len, safe_text_len_mul, take_json_object, take_json_string,
+ take_until_marker,
};
#[test]
@@ -832,4 +833,27 @@ mod tests {
assert!(matches!(error, ErrMode::Incomplete(_)));
}
+
+ #[test]
+ fn parse_buffered_event_error_includes_input_snippet() {
+ let result = parse_buffered_event(" {\"x\":1}", |input| {
+ take_json_object(input, &mut JsonObjectScanState::default())
+ });
+ let err = result.unwrap_err().to_string();
+ assert!(err.contains("near \""), "error must include snippet");
+ }
+
+ #[test]
+ fn parse_buffered_event_error_truncates_long_input() {
+ let long_input = format!(" {}", "x".repeat(100));
+ let result = parse_buffered_event(&long_input, |input| {
+ take_json_object(input, &mut JsonObjectScanState::default())
+ });
+ let err = result.unwrap_err().to_string();
+ assert!(err.contains("near \""), "error must include snippet");
+ assert!(
+ !err.contains(&long_input),
+ "snippet must be truncated for long input"
+ );
+ }
}