{"record":{"id":"8b9cf7411f2c086f","repo":"Hmbown/CodeWhale","slug":"dynamic-wrapped-serde-json-parse-error","errorCode":null,"errorMessage":"<dynamic: wrapped serde_json parse error>","messagePattern":"<dynamic: wrapped serde_json parse error>","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/large_output_router.rs","lineNumber":332,"sourceCode":"\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> {\n    use std::io::Read;\n    const MAX_MANIFEST_BYTES: u64 = 64 * 1024;\n    let mut raw = Vec::new();\n    file.open_file()?\n        .take(MAX_MANIFEST_BYTES + 1)\n        .read_to_end(&mut raw)?;\n    if raw.len() as u64 > MAX_MANIFEST_BYTES {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            \"evidence metadata exceeds limit\",\n        ));\n    }\n    serde_json::from_slice(&raw).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))\n}\n\n#[must_use]\npub fn unix_millis_now() -> u64 {\n    std::time::SystemTime::now()\n        .duration_since(std::time::UNIX_EPOCH)\n        .unwrap_or_default()\n        .as_millis()\n        .try_into()\n        .unwrap_or(u64::MAX)\n}\n\n#[must_use]\npub fn evidence_is_expired(artifact: &EvidenceArtifact, now_ms: u64) -> bool {\n    artifact.retention_state == EvidenceRetentionState::Expired\n        || now_ms > artifact.retain_until_unix_ms\n}\n","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/large_output_router.rs#L314-L350","documentation":"After the 64 KiB size check, read_evidence_metadata_file parses the sidecar bytes with serde_json::from_slice::<LegacySpilloverOwnership/EvidenceMetadata>; any serde parse failure is wrapped in io::ErrorKind::InvalidData with the serde error as its source. The sidecar is not valid JSON for the expected schema.","triggerScenarios":"read_evidence_metadata encountering a sidecar that is empty, truncated (e.g. a crash mid-write without atomic replace), or written under an older/different schema that no longer deserializes into the expected struct.","commonSituations":"Partial file from a non-atomic write or power loss; schema evolution renamed/removed a required field; manually edited JSON with a syntax error; wrong file passed as a metadata sidecar.","solutions":["Read the wrapped serde error to identify the exact offset/field that failed to parse.","Delete the corrupt sidecar and let publish_evidence_metadata regenerate it from the artifact.","If the file predates a schema change, migrate or regenerate it with the version that wrote it.","Verify writers use write_atomic so readers never see truncated JSON."],"exampleFix":"// before\ncat meta.json   # \"{'handle': ...\" — trailing garbage after truncated write\n// after\nrm meta.json    # next publish_evidence_metadata writes fresh, atomically","handlingStrategy":"try-catch","validationCode":"// shell sanity check before relying on the sidecar\npython3 -c \"import json,sys; json.load(open(sys.argv[1]))\" \"$SIDECAR\" || echo \"corrupt sidecar; regenerate\"","typeGuard":null,"tryCatchPattern":"// rust\nmatch read_evidence_metadata(&handle) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        eprintln!(\"sidecar JSON invalid ({e}); regenerating from artifact\");\n        // delete sidecar and republish\n    }\n    other => other?,\n}","preventionTips":["Write all sidecars with atomic replace so readers never see truncated JSON.","Version the sidecar schema and migrate old files instead of letting them fail deserialization.","Never hand-edit generated metadata files."],"tags":["serde","json","parse","artifacts"],"backgroundTag":"json-parse-error","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"}