spacedriveapp/spacedrive · error · CoreError

Failed to parse group_type: {}

Error message

Failed to parse group_type: {}

What it means

SpaceGroup hydration (core/src/domain/space.rs:192) parses the space_group.group_type TEXT column with serde_json::from_str into GroupType. GroupType is a serde externally-tagged enum, so valid stored values are strings like "QuickAccess", "Devices", "Locations", "Volumes", "Tags", "Sources", "Cloud", "Custom" or objects like {"Device":{"device_id":"<uuid>"}}. Any other content (renamed variant, snake_case spelling, truncated JSON) makes from_str fail and the whole query returns CoreError::Other('Failed to parse group_type: ...').

Source

Thrown at core/src/domain/space.rs:192

		let group_models = space_group::Entity::find()
			.filter(space_group::Column::Uuid.is_in(ids.to_vec()))
			.all(db)
			.await?;

		let mut results = Vec::new();

		for group_model in group_models {
			// Fetch parent space to get space_id (UUID)
			let space_model = space::Entity::find_by_id(group_model.space_id)
				.one(db)
				.await?;

			let space_id = space_model.map(|s| s.uuid).unwrap_or(group_model.uuid);

			let group_type: GroupType =
				serde_json::from_str(&group_model.group_type).map_err(|e| {
					crate::common::errors::CoreError::Other(anyhow::anyhow!(
						"Failed to parse group_type: {}",
						e
					))
				})?;

			results.push(SpaceGroup {
				id: group_model.uuid,
				space_id,
				name: group_model.name,
				group_type,
				is_collapsed: group_model.is_collapsed,
				order: group_model.order,
				created_at: group_model.created_at.into(),
			});
		}

		Ok(results)
	}

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Inspect the offending rows: `SELECT id, group_type FROM space_group;` and compare against the valid values above.
  2. Repair the data in place with valid JSON, e.g. UPDATE space_group SET group_type='"Custom"' WHERE group_type='quick_access';
  3. If a variant was renamed, keep old data loadable with #[serde(alias = "OldName")] on the enum variant instead of editing every row.
  4. Never run a daemon older than the version that created the library.

Example fix

# before: row contains invalid value
sqlite> SELECT group_type FROM space_group WHERE id=7;
quick_access

# after
sqlite> UPDATE space_group SET group_type='"QuickAccess"' WHERE id=7;
Defensive patterns

Strategy: try-catch

Validate before calling

// write-side guard: only persist group_type values that round-trip
fn valid_group_type_json(v: &str) -> bool {
    matches!(
        serde_json::from_str::<GroupType>(v),
        Ok(_)
    )
}
assert!(valid_group_type_json(&serde_json::to_string(&group_type)?));

Type guard

fn parse_group_type(s: &str) -> Option<GroupType> {
    serde_json::from_str(s).ok()
}

Try / catch

// per-row handling: quarantine the bad group, keep the rest of the space loadable
for m in group_models {
    let group_type = match serde_json::from_str(&m.group_type) {
        Ok(t) => t,
        Err(e) => {
            tracing::warn!(group_id = %m.uuid, error = %e, "skipping unparseable group_type");
            continue;
        }
    };
    // ...
}

Prevention

When it happens

Trigger: Loading spaces whose space_group rows were written by an older/newer build with different GroupType variants or casing; rows hand-edited in SQLite; a migration that wrote snake_case ('quick_access') instead of PascalCase; a variant renamed or removed between versions.

Common situations: Downgrading to an older app version against a newer library DB; running two daemon versions against the same ~/.spacedrive data dir; manual DB surgery; schema drift between desktop and a prototype client.

Understand the failure class

Related errors


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