spacedriveapp/spacedrive · error

Invalid event type: {}

Error message

Invalid event type: {}

What it means

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.

Source

Thrown at core/src/infra/sync/event_log/logger.rs:192

		let timestamp_str: String = row.try_get("", "timestamp")?;
		let device_id_str: String = row.try_get("", "device_id")?;
		let event_type_str: String = row.try_get("", "event_type")?;
		let category_str: String = row.try_get("", "category")?;
		let severity_str: String = row.try_get("", "severity")?;
		let summary: String = row.try_get("", "summary")?;
		let details_str: Option<String> = row.try_get("", "details").ok();
		let correlation_id_str: Option<String> = row.try_get("", "correlation_id").ok();
		let peer_device_id_str: Option<String> = row.try_get("", "peer_device_id").ok();
		let model_types_str: Option<String> = row.try_get("", "model_types").ok();
		let record_count: Option<i64> = row.try_get("", "record_count").ok();
		let duration_ms: Option<i64> = row.try_get("", "duration_ms").ok();

		Ok(SyncEventLog {
			id: Some(id),
			timestamp: DateTime::parse_from_rfc3339(&timestamp_str)?.with_timezone(&Utc),
			device_id: Uuid::parse_str(&device_id_str)?,
			event_type: SyncEventType::from_str(&event_type_str)
				.ok_or_else(|| anyhow::anyhow!("Invalid event type: {}", event_type_str))?,
			category: EventCategory::from_str(&category_str)
				.ok_or_else(|| anyhow::anyhow!("Invalid category: {}", category_str))?,
			severity: EventSeverity::from_str(&severity_str)
				.ok_or_else(|| anyhow::anyhow!("Invalid severity: {}", severity_str))?,
			summary,
			details: details_str
				.as_ref()
				.and_then(|s| serde_json::from_str(s).ok()),
			correlation_id: correlation_id_str
				.as_ref()
				.and_then(|s| Uuid::parse_str(s).ok()),
			peer_device_id: peer_device_id_str
				.as_ref()
				.and_then(|s| Uuid::parse_str(s).ok()),
			model_types: model_types_str.map(|s| s.split(',').map(|t| t.to_string()).collect()),
			record_count: record_count.map(|c| c as u64),
			duration_ms: duration_ms.map(|d| d as u64),
		})

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Check which tokens exist: `SELECT DISTINCT event_type FROM sync_event_log ORDER BY timestamp DESC;` and compare with the list above.
  2. 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).
  3. 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.
  4. Purge old events with the existing retention query (logger.rs DELETE FROM sync_event_log WHERE timestamp < ?).

Example fix

// before: from_str returns None -> anyhow error for the page
"sync_error_occurred" => unreachable!(),

// after: add the token (or map unknowns)
pub fn from_str(s: &str) -> Option<Self> {
    match s {
        // ... existing arms ...
        "sync_error_occurred" | "sync_error" => Some(Self::SyncError),
        _ => None,
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// read-side tolerant parsing: accept known tokens, mark the rest unknown
fn parse_event_type(s: &str) -> Option<SyncEventType> {
    SyncEventType::from_str(s)
}

Type guard

fn is_known_event_type(s: &str) -> bool {
    SyncEventType::from_str(s).is_some()
}

Try / catch

// per-row catch keeps one unknown token from failing the whole event page
let event_type = match SyncEventType::from_str(&event_type_str) {
    Some(t) => t,
    None => {
        tracing::warn!(event_type = %event_type_str, "unknown event type, skipping row");
        continue;
    }
};

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16). Data as JSON: /api/errors/bfc2a8eb96a1afef. Report an issue: GitHub.