{"record":{"id":"bfc2a8eb96a1afef","repo":"spacedriveapp/spacedrive","slug":"invalid-event-type-bfc2a8","errorCode":null,"errorMessage":"Invalid event type: {}","messagePattern":"Invalid event type: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/src/infra/sync/event_log/logger.rs","lineNumber":192,"sourceCode":"\t\tlet timestamp_str: String = row.try_get(\"\", \"timestamp\")?;\n\t\tlet device_id_str: String = row.try_get(\"\", \"device_id\")?;\n\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})","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/infra/sync/event_log/logger.rs#L174-L210","documentation":"The sync event log row mapper (core/src/infra/sync/event_log/logger.rs:192) converts the sync_event_log.event_type TEXT column back into SyncEventType via a hand-written from_str that only accepts exact snake_case tokens: state_transition, backfill_session_started, backfill_session_completed, backfill_session_failed, catch_up_session_started, catch_up_session_completed, batch_ingestion, backfill_request_sent, backfill_request_received, backfill_response_sent, peer_connected, peer_disconnected, sync_error. Any other string fails the whole row read (e.g. get_events page) with this anyhow error.","triggerScenarios":"Reading sync_event_log rows containing an event_type token this build does not know: rows written by a daemon from a different version that added/renamed event types, or rows inserted manually. Note the row read is all-or-nothing: one unknown token fails the entire query result.","commonSituations":"Opening the sync event viewer after switching daemon versions; a newer peer device writing to a shared DB; QA inserting fixture rows with wrong tokens; refactoring event names without a data migration.","solutions":["Check which tokens exist: `SELECT DISTINCT event_type FROM sync_event_log ORDER BY timestamp DESC;` and compare with the list above.","Delete or re-label unknown rows: DELETE FROM sync_event_log WHERE event_type NOT IN ('state_transition','backfill_session_started',...); (event log is diagnostic data, safe to prune).","If you control the enum, extend SyncEventType::from_str with the new token or add a catch-all Unknown variant so old builds degrade instead of failing.","Purge old events with the existing retention query (logger.rs DELETE FROM sync_event_log WHERE timestamp < ?)."],"exampleFix":"// before: from_str returns None -> anyhow error for the page\n\"sync_error_occurred\" => unreachable!(),\n\n// after: add the token (or map unknowns)\npub fn from_str(s: &str) -> Option<Self> {\n    match s {\n        // ... existing arms ...\n        \"sync_error_occurred\" | \"sync_error\" => Some(Self::SyncError),\n        _ => None,\n    }\n}","handlingStrategy":"validation","validationCode":"// read-side tolerant parsing: accept known tokens, mark the rest unknown\nfn parse_event_type(s: &str) -> Option<SyncEventType> {\n    SyncEventType::from_str(s)\n}","typeGuard":"fn is_known_event_type(s: &str) -> bool {\n    SyncEventType::from_str(s).is_some()\n}","tryCatchPattern":"// per-row catch keeps one unknown token from failing the whole event page\nlet event_type = match SyncEventType::from_str(&event_type_str) {\n    Some(t) => t,\n    None => {\n        tracing::warn!(event_type = %event_type_str, \"unknown event type, skipping row\");\n        continue;\n    }\n};","preventionTips":["Write event_type only via SyncEventType::as_str().","When adding event types, also handle them in from_str of older readers or purge old rows.","Treat sync_event_log as disposable diagnostic data; prune with the retention DELETE on version upgrades."],"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"}