{"record":{"id":"af343797682fd043","repo":"Hmbown/CodeWhale","slug":"dynamic-wrapped-serde-json-serialization-error","errorCode":null,"errorMessage":"<dynamic: wrapped serde_json serialization error>","messagePattern":"<dynamic: wrapped serde_json serialization error>","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/large_output_router.rs","lineNumber":301,"sourceCode":"        std::env::var(\"CODEWHALE_CLASSIC_OUTPUT_ROUTING\")\n            .ok()\n            .as_deref()\n            .map(str::trim),\n        Some(\"0\" | \"false\" | \"no\" | \"off\")\n    )\n}\n\n#[must_use]\npub fn evidence_metadata_relative_path(handle: &str) -> PathBuf {\n    PathBuf::from(crate::artifacts::ARTIFACTS_DIR_NAME).join(format!(\"{handle}.evidence.json\"))\n}\n\npub fn publish_evidence_metadata(\n    session_id: &str,\n    artifact: &EvidenceArtifact,\n) -> io::Result<PathBuf> {\n    let bytes = serde_json::to_vec_pretty(artifact)\n        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;\n    crate::artifacts::write_session_relative_immutable(\n        session_id,\n        &evidence_metadata_relative_path(&artifact.handle),\n        &bytes,\n    )\n}\n\npub fn read_evidence_metadata(session_id: &str, handle: &str) -> io::Result<EvidenceArtifact> {\n    let relative = evidence_metadata_relative_path(handle);\n    let file = crate::artifacts::open_session_relative(session_id, &relative, false)?;\n    read_evidence_metadata_file(&file)\n}\n\n/// Bounded, no-follow read shared by publication/replay and authenticated HTTP\n/// retrieval. The caller chooses the existing session-root authority.\npub(crate) fn read_evidence_metadata_file(\n    file: &crate::fleet::files::WorkspaceFile,\n) -> io::Result<EvidenceArtifact> {","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/large_output_router.rs#L283-L319","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nstruct EvidenceArtifact { spans: HashMap<u64, Span> }\n// after\nstruct EvidenceArtifact { spans: BTreeMap<String, Span> }  // JSON keys must be strings\n// and when inserting: spans.insert(id.to_string(), span);","handlingStrategy":"try-catch","validationCode":"// pre-validate values that serde_json cannot represent\nif artifact.values.iter().any(|v| v.is_nan() || v.is_infinite()) { return Err(\"non-finite float in artifact\"); }","typeGuard":null,"tryCatchPattern":"// rust\nlet bytes = serde_json::to_vec_pretty(artifact)\n    .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;\n// catch: log the wrapped serde error (it names the failing field) before propagating","preventionTips":["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."],"tags":["serde","json","serialization","artifacts"],"backgroundTag":"json-serialization-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T10:30:35.592Z"}