spacedriveapp/spacedrive · warning · anyhow::Error

Source entry not found

Error message

Source entry not found

What it means

A sidecar row has source_entry_id set, but entry::find_by_id returned no entry: the reference is orphaned. The lookup happens while processing reference sidecars, and the hard error aborts the whole operation instead of skipping the orphaned row.

Source

Thrown at core/src/service/sidecar_manager.rs:430

		content_uuid: &Uuid,
	) -> Result<()> {
		let db = library.db();

		// Find all reference sidecars for this content
		let reference_sidecars = Sidecar::find()
			.filter(sidecar::Column::ContentUuid.eq(*content_uuid))
			.filter(sidecar::Column::SourceEntryId.is_not_null())
			.all(db.conn())
			.await?;

		for sidecar in reference_sidecars {
			if let Some(source_entry_id) = sidecar.source_entry_id {
				// Get the source entry to find the file path
				use crate::infra::db::entities::entry;
				let source_entry = entry::Entity::find_by_id(source_entry_id)
					.one(db.conn())
					.await?
					.ok_or_else(|| anyhow::anyhow!("Source entry not found"))?;

				// Compute the target sidecar path
				let kind = sidecar
					.kind
					.as_str()
					.try_into()
					.map_err(|e: String| anyhow::anyhow!(e))?;
				let variant = SidecarVariant::new(&sidecar.variant);
				let format = sidecar
					.format
					.as_str()
					.try_into()
					.map_err(|e: String| anyhow::anyhow!(e))?;

				let target_path = self
					.compute_path(&library.id(), content_uuid, &kind, &variant, &format)
					.await?;

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Add cleanup that removes sidecar rows whose source_entry_id no longer resolves, and run it once to fix existing orphans
  2. Enforce referential integrity on entry delete (cascade or explicit sidecar cleanup)
  3. Skip orphaned sidecars with a warning instead of failing the operation

Example fix

// before
let source_entry = entry::Entity::find_by_id(source_entry_id).one(db.conn()).await?.ok_or_else(|| anyhow::anyhow!("Source entry not found"))?;

// after
let Some(source_entry) = entry::Entity::find_by_id(source_entry_id).one(db.conn()).await? else {
    warn!(%source_entry_id, "orphaned sidecar: source entry missing, skipping");
    continue;
};
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-filter reference sidecars to those with a resolvable source entry
let ids: Vec<Uuid> = reference_sidecars.iter().filter_map(|s| s.source_entry_id).collect();
let existing: HashSet<Uuid> = entry::Entity::find().filter(entry::Column::Id.is_in(ids)).all(db).await?.into_iter().map(|e| e.id).collect();

Type guard

fn has_source_entry(sidecar: &SidecarModel, existing: &HashSet<Uuid>) -> bool {
    sidecar.source_entry_id.is_none_or(|id| existing.contains(&id))
}

Try / catch

match entry::Entity::find_by_id(source_entry_id).one(db.conn()).await? {
    Some(entry) => { /* use it */ }
    None => {
        warn!(%source_entry_id, "orphaned sidecar: source entry missing, skipping");
        continue;
    }
}

Prevention

When it happens

Trigger: The source entry was deleted while its sidecars survived (missing cascade delete); a restored or edited database with referential inconsistencies; sidecars written for ephemeral entries that were later pruned.

Common situations: File deletion with failed cleanup; sync conflicts creating orphan rows; database imports.

Related errors


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