{"record":{"id":"d78d0273113af18d","repo":"spacedriveapp/spacedrive","slug":"invalid-category","errorCode":null,"errorMessage":"Invalid category: {}","messagePattern":"Invalid category: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/src/infra/sync/event_log/logger.rs","lineNumber":194,"sourceCode":"\t\tlet event_type_str: String = row.try_get(\"\", \"event_type\")?;\n\t\tlet category_str: String = row.try_get(\"\", \"category\")?;\n\t\tlet severity_str: String = row.try_get(\"\", \"severity\")?;\n\t\tlet summary: String = row.try_get(\"\", \"summary\")?;\n\t\tlet details_str: Option<String> = row.try_get(\"\", \"details\").ok();\n\t\tlet correlation_id_str: Option<String> = row.try_get(\"\", \"correlation_id\").ok();\n\t\tlet peer_device_id_str: Option<String> = row.try_get(\"\", \"peer_device_id\").ok();\n\t\tlet model_types_str: Option<String> = row.try_get(\"\", \"model_types\").ok();\n\t\tlet record_count: Option<i64> = row.try_get(\"\", \"record_count\").ok();\n\t\tlet duration_ms: Option<i64> = row.try_get(\"\", \"duration_ms\").ok();\n\n\t\tOk(SyncEventLog {\n\t\t\tid: Some(id),\n\t\t\ttimestamp: DateTime::parse_from_rfc3339(&timestamp_str)?.with_timezone(&Utc),\n\t\t\tdevice_id: Uuid::parse_str(&device_id_str)?,\n\t\t\tevent_type: SyncEventType::from_str(&event_type_str)\n\t\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Invalid event type: {}\", event_type_str))?,\n\t\t\tcategory: EventCategory::from_str(&category_str)\n\t\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Invalid category: {}\", category_str))?,\n\t\t\tseverity: EventSeverity::from_str(&severity_str)\n\t\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Invalid severity: {}\", severity_str))?,\n\t\t\tsummary,\n\t\t\tdetails: details_str\n\t\t\t\t.as_ref()\n\t\t\t\t.and_then(|s| serde_json::from_str(s).ok()),\n\t\t\tcorrelation_id: correlation_id_str\n\t\t\t\t.as_ref()\n\t\t\t\t.and_then(|s| Uuid::parse_str(s).ok()),\n\t\t\tpeer_device_id: peer_device_id_str\n\t\t\t\t.as_ref()\n\t\t\t\t.and_then(|s| Uuid::parse_str(s).ok()),\n\t\t\tmodel_types: model_types_str.map(|s| s.split(',').map(|t| t.to_string()).collect()),\n\t\t\trecord_count: record_count.map(|c| c as u64),\n\t\t\tduration_ms: duration_ms.map(|d| d as u64),\n\t\t})\n\t}\n","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/infra/sync/event_log/logger.rs#L176-L212","documentation":"Row mapper at core/src/infra/sync/event_log/logger.rs:194 parses sync_event_log.category via EventCategory::from_str, which accepts exactly four snake_case values: lifecycle, data_flow, network, error. Any other string in the category column makes the whole event-log read (row_to_event) fail with this error.","triggerScenarios":"A sync_event_log row whose category is not one of the four tokens: written by a different core version, inserted by fixtures/scripts, or hand-edited. Because category is written by EventCategory::as_str(), core-generated rows are always valid, so this almost always means external writes or version skew.","commonSituations":"QA seeding the event log with made-up categories; a build that renamed 'data_flow' to something else; reading a DB created by a dev branch.","solutions":["Enumerate values: `SELECT DISTINCT category FROM sync_event_log;` and compare to lifecycle/data_flow/network/error.","Prune or normalize bad rows (event log is diagnostic, pruning is safe): UPDATE sync_event_log SET category='error' WHERE category='errors'; or DELETE them.","When renaming categories in code, add a legacy arm to EventCategory::from_str or ship a data migration."],"exampleFix":"# before\nsqlite> SELECT DISTINCT category FROM sync_event_log;\nerrors\n\n# after\nsqlite> UPDATE sync_event_log SET category='error' WHERE category='errors';","handlingStrategy":"validation","validationCode":"// reject fixture/manual writes whose category is not a real token\nfn valid_category(s: &str) -> bool {\n    EventCategory::from_str(s).is_some()\n}","typeGuard":"fn parse_category(s: &str) -> Option<EventCategory> {\n    EventCategory::from_str(s)\n}","tryCatchPattern":"// skip rows with unknown categories instead of failing the listing\nlet category = match EventCategory::from_str(&category_str) {\n    Some(c) => c,\n    None => { tracing::warn!(category = %category_str, \"unknown category\"); continue; }\n};","preventionTips":["Always insert categories via EventCategory::as_str().","Seed test data through the logger API, never raw SQL.","Add legacy mappings in from_str when renaming categories."],"tags":["sync","event-log","database","version-skew"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}