Hmbown/CodeWhale · error · io::Error
<dynamic: wrapped serde_json serialization error>
Error message
<dynamic: wrapped serde_json serialization error>
What it means
publish_evidence_metadata serializes an EvidenceArtifact to pretty JSON with serde_json::to_vec_pretty before writing it to the session's immutable artifact store. Serialization failures are wrapped in io::ErrorKind::InvalidData with the serde error as the source. Since the input is a strongly typed struct this almost always indicates a value serde cannot represent, such as a map key that is not a string or a non-string key type.
Solutions
- Inspect the wrapped serde error message to find the offending field/type in EvidenceArtifact.
- Replace non-string map keys with String (or use serde_json's string-keyed maps), and sanitize f64 values (reject/replace NaN and Infinity).
- Add #[serde(skip_serializing_if)] for optional/awkward fields, or a custom Serialize for problematic types.
- Add a unit test serializing the artifact shape that failed to catch regressions.
Example fix
// before
struct EvidenceArtifact { spans: HashMap<u64, Span> }
// after
struct EvidenceArtifact { spans: BTreeMap<String, Span> } // JSON keys must be strings
// and when inserting: spans.insert(id.to_string(), span); Defensive patterns
Strategy: try-catch
Validate before calling
// pre-validate values that serde_json cannot represent
if artifact.values.iter().any(|v| v.is_nan() || v.is_infinite()) { return Err("non-finite float in artifact"); } Try / catch
// rust
let bytes = serde_json::to_vec_pretty(artifact)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
// catch: log the wrapped serde error (it names the failing field) before propagating Prevention
- Keep JSON map keys as String; convert numeric keys with .to_string() at insertion.
- Sanitize floats (reject or stringify NaN/Infinity) before building artifacts.
- Add a round-trip serialize test for EvidenceArtifact after every schema change.
When it happens
Trigger: publish_image, publish_offloaded_context, or apply_adaptive_evidence_inner calling publish_evidence_metadata when the EvidenceArtifact (or nested data) fails serde_json serialization — e.g. a HashMap with non-string keys, NaN/f64 in a position requiring finite JSON numbers, or a custom Serialize impl that errors.
Common situations: A schema change added a field with a non-JSON-serializable type; f64 NaN/Infinity produced upstream; a BTreeMap<u64, _> or HashMap<i32, _> leaked into the artifact struct.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
- <dynamic: wrapped serde_json parse error>
- <dynamic: wrapped serde_json serialization error>
- (serde_json deserialization error wrapped as…
- <serde_json serialization error>
- (serde_json serialization error wrapped as…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/af343797682fd043.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/large_output_router.rs:301
std::env::var("CODEWHALE_CLASSIC_OUTPUT_ROUTING")
.ok()
.as_deref()
.map(str::trim),
Some("0" | "false" | "no" | "off")
)
}
#[must_use]
pub fn evidence_metadata_relative_path(handle: &str) -> PathBuf {
PathBuf::from(crate::artifacts::ARTIFACTS_DIR_NAME).join(format!("{handle}.evidence.json"))
}
pub fn publish_evidence_metadata(
session_id: &str,
artifact: &EvidenceArtifact,
) -> io::Result<PathBuf> {
let bytes = serde_json::to_vec_pretty(artifact)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
crate::artifacts::write_session_relative_immutable(
session_id,
&evidence_metadata_relative_path(&artifact.handle),
&bytes,
)
}
pub fn read_evidence_metadata(session_id: &str, handle: &str) -> io::Result<EvidenceArtifact> {
let relative = evidence_metadata_relative_path(handle);
let file = crate::artifacts::open_session_relative(session_id, &relative, false)?;
read_evidence_metadata_file(&file)
}
/// Bounded, no-follow read shared by publication/replay and authenticated HTTP
/// retrieval. The caller chooses the existing session-root authority.
pub(crate) fn read_evidence_metadata_file(
file: &crate::fleet::files::WorkspaceFile,
) -> io::Result<EvidenceArtifact> {View on GitHub (pinned to 73e0f67d83)