ch-remote: Fix error message deserialization from JSON response

server_api_error_display_modifier deserialized the JSON error response
into a `Vec<&str>`.  However, if the error message contained escaped
characters, it could not deserialize it into a borrowed string `&str`
because unescaping requires allocation. This resulted in a
deserialization error and a failure to print the error chain.

This change switches the deserialization target to `Vec<String>` to
allow allocation.

Signed-off-by: Andrei Vagin <avagin@google.com>
This commit is contained in:
Andrei Vagin
2026-05-29 01:06:23 +00:00
committed by Rob Bradford
parent 1b0dfc0da3
commit f9709d6f92

View File

@@ -1247,7 +1247,7 @@ fn main() {
let body = body.as_ref().map_or("", |body| body.as_str()); let body = body.as_ref().map_or("", |body| body.as_str());
// Retrieve the list of error messages back. // Retrieve the list of error messages back.
let lines: Vec<&str> = match serde_json::from_str(body) { let lines: Vec<String> = match serde_json::from_str(body) {
Ok(json) => json, Ok(json) => json,
Err(e) => { Err(e) => {
return Some(format!( return Some(format!(
@@ -1259,7 +1259,8 @@ fn main() {
let error_status = format!("Server responded with {status_code:?}"); let error_status = format!("Server responded with {status_code:?}");
// Prepend the error status line to the lines iter. // Prepend the error status line to the lines iter.
let lines = std::iter::once(error_status.as_str()).chain(lines); let lines =
std::iter::once(error_status.as_str()).chain(lines.iter().map(|s| s.as_str()));
let error_msg_multiline = lines let error_msg_multiline = lines
.enumerate() .enumerate()
.map(|(index, error_msg)| (index + level, error_msg)) .map(|(index, error_msg)| (index + level, error_msg))
@@ -1321,4 +1322,17 @@ mod unit_tests {
assert_args_sorted(|| command.get_arguments()); assert_args_sorted(|| command.get_arguments());
} }
} }
#[test]
fn test_error_deserialization() {
let body = r#"["Error from API","The VM could not be snapshotted","Cannot send VM snapshot","Failed to send migratable component snapshot","Destination is not a directory: \"/tmp/ch.dump\""]"#;
let lines: Result<Vec<String>, _> = serde_json::from_str(body);
assert!(lines.is_ok());
let lines = lines.unwrap();
assert_eq!(lines.len(), 5);
assert_eq!(
lines[4],
r#"Destination is not a directory: "/tmp/ch.dump""#
);
}
} }