{"record":{"id":"803c87272f8ee311","repo":"BloopAI/vibe-kanban","slug":"workspace-serialization-should-not-fail","errorCode":null,"errorMessage":"Workspace serialization should not fail","messagePattern":"Workspace serialization should not fail","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/services/src/services/events/patches.rs","lineNumber":72,"sourceCode":"\n/// Helper functions for creating workspace-specific patches\npub mod workspace_patch {\n    use super::*;\n\n    fn workspace_path(workspace_id: Uuid) -> String {\n        format!(\n            \"/workspaces/{}\",\n            escape_pointer_segment(&workspace_id.to_string())\n        )\n    }\n\n    pub fn add(workspace: &WorkspaceWithStatus) -> Patch {\n        Patch(vec![PatchOperation::Add(AddOperation {\n            path: workspace_path(workspace.id)\n                .try_into()\n                .expect(\"Workspace path should be valid\"),\n            value: serde_json::to_value(workspace)\n                .expect(\"Workspace serialization should not fail\"),\n        })])\n    }\n\n    pub fn replace(workspace: &WorkspaceWithStatus) -> Patch {\n        Patch(vec![PatchOperation::Replace(ReplaceOperation {\n            path: workspace_path(workspace.id)\n                .try_into()\n                .expect(\"Workspace path should be valid\"),\n            value: serde_json::to_value(workspace)\n                .expect(\"Workspace serialization should not fail\"),\n        })])\n    }\n\n    pub fn remove(workspace_id: Uuid) -> Patch {\n        Patch(vec![PatchOperation::Remove(RemoveOperation {\n            path: workspace_path(workspace_id)\n                .try_into()\n                .expect(\"Workspace path should be valid\"),","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/crates/services/src/services/events/patches.rs#L54-L90","documentation":"This panic comes from `.expect()` on `serde_json::to_value(workspace)` in `workspace_patch::add` (crates/services/src/services/events/patches.rs:72). The library assumes `WorkspaceWithStatus` always serializes to JSON; serde returns `Err` only when a custom `Serialize` implementation errors (e.g. serializing a map with non-string keys or a manual impl returning Err). This is treated as an internal invariant, not an expected runtime failure.","triggerScenarios":"Calling `workspace_patch::add(&WorkspaceWithStatus)` when `serde_json::to_value` fails — only possible if a type inside `WorkspaceWithStatus` has a custom/fallible `Serialize` impl (e.g. serializing a HashMap with non-string keys, or a manual impl returning Err).","commonSituations":"Developers encounter this after adding a field with a hand-written `Serialize` implementation that can fail, or after swapping a struct field to a map keyed by UUIDs/other non-string types.","solutions":["Inspect `WorkspaceWithStatus` (and nested types) for custom `Serialize` impls that can return Err; fix the impl so it cannot fail.","If a field serializes a map with non-string keys, convert keys to strings first (e.g. BTreeMap<String, T>) before serializing.","If fallibility is real, replace `.expect(...)` with error propagation (return Result<Patch, serde_json::Error>) and handle at the event-emission layer.","Regenerate/verify derived types with `pnpm run generate-types` after changing the struct."],"exampleFix":"// before\nvalue: serde_json::to_value(workspace)\n    .expect(\"Workspace serialization should not fail\"),\n// after\nvalue: serde_json::to_value(workspace).unwrap_or_else(|e| {\n    panic!(\"failed to serialize workspace {}: {e}\", workspace.id)\n}),\n// or propagate: return Result<Patch, serde_json::Error>","handlingStrategy":"validation","validationCode":"let value = serde_json::to_value(&workspace)\n    .map_err(|e| anyhow::anyhow!(\"workspace serialization failed: {e}\"))?;\n// proceed with Patch construction using `value`","typeGuard":"fn serializable<T: serde::Serialize>(v: &T) -> Option<serde_json::Value> {\n    serde_json::to_value(v).ok()\n}","tryCatchPattern":"match serde_json::to_value(workspace) {\n    Ok(v) => /* build patch with v */,\n    Err(e) => log::error!(\"workspace {} serialization failed: {e}\", workspace.id),\n}","preventionTips":["Prefer derived #[derive(Serialize)] over hand-written fallible impls.","Avoid serializing maps with non-string keys; pre-convert keys to String.","Keep Rust and TS types in sync via pnpm run generate-types.","Add a round-trip test: to_value then from_value for WorkspaceWithStatus."],"tags":["rust","serde","serialization","panic"],"backgroundTag":"serde-serialization-failed","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}