From cef4b0e7d1fe2f7512526ccf3eb6ef3f0158a8da Mon Sep 17 00:00:00 2001 From: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:09:01 -0500 Subject: [PATCH] Ensure pre-formatted JSON data doesn't contain trailing null bytes. (#1332) When serializing Python objects to JSON, `orjson` includes a trailing null byte since it's producing a C-string which is null-terminated. However, when sending HTTP multipart data, we send the JSON with an explicit content length value, so the trailing null byte is neither needed nor expected. So strip the trailing null (if present) before sending `inputs` and `outputs`. --- .../src/client/blocking/processor.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/rust/crates/langsmith-tracing-client/src/client/blocking/processor.rs b/rust/crates/langsmith-tracing-client/src/client/blocking/processor.rs index 8005e0e55..2063516bf 100644 --- a/rust/crates/langsmith-tracing-client/src/client/blocking/processor.rs +++ b/rust/crates/langsmith-tracing-client/src/client/blocking/processor.rs @@ -117,11 +117,19 @@ impl RunProcessor { to_vec(&run_create).unwrap(), // TODO: get rid of unwrap )); - if let Some(inputs) = io.inputs { + // Ensure that pre-formatted JSON data represented as bytes + // doesn't end in trailing null bytes, since we'll be pasting it verbatim + // into an HTTP multipart request which carries an explicit length header. + if let Some(mut inputs) = io.inputs { + if inputs.last() == Some(&0) { + inputs.pop().expect("popping trailing null byte failed"); + } json_data.push((format!("post.{}.inputs", run_id), inputs)); } - - if let Some(outputs) = io.outputs { + if let Some(mut outputs) = io.outputs { + if outputs.last() == Some(&0) { + outputs.pop().expect("popping trailing null byte failed"); + } json_data.push((format!("post.{}.outputs", run_id), outputs)); } @@ -150,7 +158,13 @@ impl RunProcessor { to_vec(&run_update).unwrap(), // TODO: get rid of unwrap )); - if let Some(outputs) = io.outputs { + // Ensure that pre-formatted JSON data represented as bytes + // doesn't end in trailing null bytes, since we'll be pasting it verbatim + // into an HTTP multipart request which carries an explicit length header. + if let Some(mut outputs) = io.outputs { + if outputs.last() == Some(&0) { + outputs.pop().expect("popping trailing null byte failed"); + } json_data.push((format!("patch.{}.outputs", run_id), outputs)); }