{"record":{"id":"507b15dca68820cf","repo":"Hmbown/CodeWhale","slug":"dynamic-wrapped-serde-json-serialization-error-truncate","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/truncate.rs","lineNumber":153,"sourceCode":"    payload_path: &Path,\n    session_id: &str,\n    bytes: &[u8],\n) -> io::Result<PathBuf> {\n    if session_id.trim().is_empty() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"legacy spillover ownership requires a session id\",\n        ));\n    }\n    let ownership = LegacySpilloverOwnership {\n        schema_version: LEGACY_SPILLOVER_OWNER_SCHEMA_VERSION,\n        origin_session: session_id.to_string(),\n        digest: crate::hashing::sha256_hex(bytes),\n        size_bytes: bytes.len().try_into().unwrap_or(u64::MAX),\n    };\n    let sidecar = legacy_spillover_ownership_path(payload_path);\n    let encoded = serde_json::to_vec_pretty(&ownership)\n        .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;\n    crate::utils::write_atomic(&sidecar, &encoded)?;\n    Ok(sidecar)\n}\n\npub(crate) fn read_legacy_spillover_ownership(\n    payload_path: &Path,\n) -> io::Result<LegacySpilloverOwnership> {\n    let sidecar = legacy_spillover_ownership_path(payload_path);\n    if std::fs::symlink_metadata(&sidecar)?\n        .file_type()\n        .is_symlink()\n    {\n        return Err(io::Error::new(\n            io::ErrorKind::PermissionDenied,\n            \"legacy spillover ownership sidecar must not be a symlink\",\n        ));\n    }\n    let ownership = serde_json::from_slice::<LegacySpilloverOwnership>(&std::fs::read(sidecar)?)","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/truncate.rs#L135-L171","documentation":"publish_legacy_spillover_ownership serializes the LegacySpilloverOwnership struct (schema version, origin session, digest, size) with serde_json::to_vec_pretty before an atomic write. Serialization errors are wrapped in io::ErrorKind::InvalidData with the serde error attached. Given the simple field set, failures point to a type serde_json cannot represent, most commonly a non-string map key or invalid float introduced by a schema change.","triggerScenarios":"apply_spillover_inner -> publish_legacy_spillover_ownership when serde_json::to_vec_pretty(&ownership) errors — e.g. after adding a field with a non-JSON-compatible type (HashMap<u64,_>, f64::NAN) or a failing custom Serialize impl.","commonSituations":"Recent schema evolution of LegacySpilloverOwnership added a problematic field; NaN/Infinity sizes or digests stored as floats; a custom serializer returning Err.","solutions":["Read the wrapped serde error to find the offending field in LegacySpilloverOwnership.","Change non-string map keys to String/String-keyed maps and sanitize float fields (no NaN/Infinity).","Use #[serde(skip_serializing_if = \"Option::is_none\")] or a custom Serialize for awkward types.","Pin the struct with a round-trip unit test so future schema changes cannot silently break serialization."],"exampleFix":"// before\nstruct LegacySpilloverOwnership { tags: HashMap<u32, String>, ... }\n// after\nstruct LegacySpilloverOwnership { tags: BTreeMap<String, String>, ... }","handlingStrategy":"try-catch","validationCode":"// pre-check types serde_json cannot represent when extending the struct\n// reject non-string map keys and non-finite floats before constructing LegacySpilloverOwnership","typeGuard":null,"tryCatchPattern":"// rust\nlet encoded = serde_json::to_vec_pretty(&ownership)\n    .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?; // log wrapped serde error to find the field","preventionTips":["Use only JSON-native types (String keys, finite numbers) in LegacySpilloverOwnership fields.","Run a serialize/deserialize round-trip test whenever the struct's schema changes."],"tags":["serde","json","serialization","spillover"],"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"}