spacedriveapp/spacedrive · error

Entry has no content_id

Error message

Entry has no content_id

What it means

The OCR processor requires entry.content_id because extracted text is written into the content_identity row. process() unwraps the Option and errors when None: the entry passed the mime-type check but was never identified (no content identity created), so there is nowhere to store OCR output.

Source

Thrown at core/src/ops/media/ocr/processor.rs:75

		}

		if entry.content_id.is_none() {
			return false;
		}

		entry.mime_type.as_ref().map_or(false, |m| {
			super::is_ocr_supported(m, self.library.core_context().file_type_registry())
		})
	}

	pub async fn process(
		&self,
		db: &sea_orm::DatabaseConnection,
		entry: &ProcessorEntry,
	) -> Result<ProcessorResult> {
		let content_id = entry
			.content_id
			.ok_or_else(|| anyhow::anyhow!("Entry has no content_id"))?;

		debug!("→ Extracting text via OCR for: {}", entry.path.display());

		// Extract text
		let extracted_text = super::extract_text_from_file(&entry.path, &self.languages).await?;

		if extracted_text.is_empty() {
			debug!("No text extracted from: {}", entry.path.display());
			return Ok(ProcessorResult::success(0, 0));
		}

		debug!("✓ Extracted {} characters of text", extracted_text.len());

		// Update content_identity with extracted text
		use crate::infra::db::entities::content_identity;

		let ci = content_identity::Entity::find_by_id(content_id)
			.one(db)

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Ensure the identifier processor runs before OCR in the pipeline ordering
  2. Add a content_id requirement to the processor's wants_to_process check so unqualified entries are filtered, not errored
  3. Re-run identification on affected entries, then re-queue OCR

Example fix

// before (wants_to_process)
entry.mime_type.as_ref().map_or(false, |m| {
    super::is_ocr_supported(m, self.library.core_context().file_type_registry())
})

// after: also require a content identity, mirroring process()'s hard requirement
entry.mime_type.as_ref().map_or(false, |m| {
    super::is_ocr_supported(m, self.library.core_context().file_type_registry())
}) && entry.content_id.is_some()
Defensive patterns

Strategy: type-guard

Validate before calling

// Only enqueue OCR when a content identity exists
if entry.content_id.is_some() {
    ocr_processor.enqueue(entry).await?;
}

Type guard

fn is_ocr_eligible(entry: &ProcessorEntry, registry: &FileTypeRegistry) -> bool {
    entry.content_id.is_some()
        && entry
            .mime_type
            .as_ref()
            .map_or(false, |m| super::is_ocr_supported(m, registry))
}

Try / catch

match ocr.process(db, &entry).await {
    Ok(res) => { /* aggregate results */ }
    Err(e) if e.to_string().contains("Entry has no content_id") => {
        tracing::debug!(path = %entry.path.display(), "skipping OCR: entry not yet identified");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Running the OCR processor on entries the identifier has not processed yet (pipeline ordering wrong); entries whose identification failed or was skipped; manually enqueuing entries into the processor without the identify step.

Common situations: Processor registry ordering changed so OCR runs before identification; a new file picked up mid-write before identify completed; identification errors silently skipped an entry.

Related errors


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