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

  1. Inspect the wrapped serde error message to find the offending field/type in EvidenceArtifact.
  2. Replace non-string map keys with String (or use serde_json's string-keyed maps), and sanitize f64 values (reject/replace NaN and Infinity).
  3. Add #[serde(skip_serializing_if)] for optional/awkward fields, or a custom Serialize for problematic types.
  4. 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

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


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)