Hmbown/CodeWhale · error · std::io::Error
(serde_json serialization error wrapped as…
Error message
(serde_json serialization error wrapped as io::ErrorKind::InvalidData)
What it means
In `save_offline_queue_state`, the cloned `OfflineQueueState` is serialized with `serde_json::to_string_pretty` before an atomic write; any serialization failure is wrapped as an `io::ErrorKind::InvalidData` io::Error whose inner error is the serde error. In practice this is rare because the struct is JSON-safe, but a poisoned/invalid custom value or an out-of-range numeric field can trip it.
Solutions
- Inspect the inner serde error message (`{error}` source) to identify the offending field.
- Sanitize numeric fields (no NaN/Infinity) before saving.
- Ensure all nested types implement Serialize with string map keys.
Example fix
// before
state.retry_at = f64::NAN;
manager.save_offline_queue_state(&state, Some(id))?;
// after
if state.retry_at.is_finite() {
manager.save_offline_queue_state(&state, Some(id))?;
} Defensive patterns
Strategy: validation
Validate before calling
serde_json::to_string_pretty(&state).map_err(|e| e.to_string())?; // dry-run serialize before saving
Try / catch
match manager.save_offline_queue_state(&state, Some(id)) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
eprintln!("queue state not serializable: {e}");
}
other => other?,
} Prevention
- Keep OfflineQueueState fields finite (no NaN/Infinity) and JSON-safe.
- Dry-run serialize custom state before persisting.
When it happens
Trigger: Calling `save_offline_queue_state` with an `OfflineQueueState` that serde_json cannot serialize (non-string map keys in nested fields, NaN/Infinity floats, invalid values in custom Serialize impls).
Common situations: Custom fields added to the queue state containing NaN from computed timings; hand-built state structs populated from untrusted parsing output.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- (serde_json deserialization error wrapped as…
- <dynamic: wrapped serde_json parse error>
- Offline queue schema v
- <serde_json deserialization error>
- (serde_json deserialization error wrapped as…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/5955eab235e8e662.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/session_manager.rs:2170
pub fn save_offline_queue_state(
&self,
state: &OfflineQueueState,
session_id: Option<&str>,
) -> std::io::Result<PathBuf> {
let session_id = session_id.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Offline queue cannot be parked without a session id",
)
})?;
let path = self.validated_offline_queue_path(session_id)?;
fs::create_dir_all(self.checkpoints_dir())?;
let mut owned = state.clone();
// The stamp is redundant with the file name; it stays because the UI's
// restore path still compares it against the live session id.
owned.session_id = Some(self.validated_session_id(session_id)?.to_string());
let content = serde_json::to_string_pretty(&owned)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
write_atomic(&path, content.as_bytes())?;
Ok(path)
}
/// Load one session's parked offline queue if present.
pub fn load_offline_queue_state(
&self,
session_id: &str,
) -> std::io::Result<Option<OfflineQueueState>> {
let path = self.validated_offline_queue_path(session_id)?;
Ok(match Self::read_offline_queue_file(&path)? {
Some(state) => Some(state),
None => self.adopt_legacy_offline_queue(session_id, &path)?,
})
}
/// Remove one named session's parked offline queue.
pub fn clear_offline_queue_state_for(&self, session_id: &str) -> std::io::Result<()> {View on GitHub (pinned to 433685b202)