{"record":{"id":"9dfaed3966dc6500","repo":"spacedriveapp/spacedrive","slug":"location-has-no-root-entry","errorCode":null,"errorMessage":"Location {} has no root entry","messagePattern":"Location (.+?) has no root entry","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/src/ops/indexing/change_detection/persistent.rs","lineNumber":64,"sourceCode":"\t\t_location_root: &Path,\n\t\tvolume_backend: Option<Arc<dyn crate::volume::VolumeBackend>>,\n\t) -> Result<Self> {\n\t\tlet library = context\n\t\t\t.get_library(library_id)\n\t\t\t.await\n\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Library not found: {}\", library_id))?;\n\n\t\tlet db = library.db().conn().clone();\n\n\t\tlet location_record = entities::location::Entity::find()\n\t\t\t.filter(entities::location::Column::Uuid.eq(location_id))\n\t\t\t.one(&db)\n\t\t\t.await?\n\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Location not found: {}\", location_id))?;\n\n\t\tlet location_root_entry_id = location_record\n\t\t\t.entry_id\n\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Location {} has no root entry\", location_id))?;\n\n\t\tlet volume_id = location_record.volume_id.ok_or_else(|| {\n\t\t\tanyhow::anyhow!(\n\t\t\t\t\"Location {} has no volume_id - volume must be detected before change detection\",\n\t\t\t\tlocation_id\n\t\t\t)\n\t\t})?;\n\n\t\tOk(Self {\n\t\t\tcontext,\n\t\t\tlibrary_id,\n\t\t\tlocation_id,\n\t\t\tlocation_root_entry_id,\n\t\t\tvolume_id,\n\t\t\tdb,\n\t\t\tvolume_backend,\n\t\t\tentry_id_cache: HashMap::new(),\n\t\t})","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/ops/indexing/change_detection/persistent.rs#L46-L82","documentation":"The location row exists but its entry_id column is NULL, so DatabaseAdapter::new cannot learn the root entry that anchors the entry closure tree. Locations get entry_id only after the initial indexer creates the root entry; a NULL means that initialization never completed or was interrupted, and path-to-entry resolution would have no root to descend from.","triggerScenarios":"Starting persistent change detection on a location whose initial index never ran or crashed before creating the root entry; restoring a database dump from before the root-entry backfill; location creation flow interrupted between INSERT and root entry creation.","commonSituations":"Daemon killed during first index of a new location; location added but indexer job failed early; schema migration that added entry_id without backfilling existing rows.","solutions":["Run the initial indexer for the location (it creates the root entry and sets entry_id) before enabling change detection","Check location creation code to confirm it writes entry_id after creating the root entry","If migrating, backfill entry_id for existing locations from their root entry rows"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Require a rooted location before starting change detection\nlet loc = entities::location::Entity::find()\n    .filter(entities::location::Column::Uuid.eq(location_id))\n    .one(&db).await?;\nmatch loc {\n    Some(l) if l.entry_id.is_some() => { /* safe to construct DatabaseAdapter */ }\n    _ => { /* run initial indexer first, then retry */ }\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = DatabaseAdapter::new(...).await {\n    if e.to_string().contains(\"has no root entry\") {\n        // trigger initial index for this location, then re-queue change detection\n    }\n}","preventionTips":["Enforce location lifecycle order: create → initial index (sets entry_id) → change detection","Treat a NULL entry_id as 'not yet initialized' in operational dashboards","Add migration backfills when introducing entry_id to existing schemas"],"tags":["indexing","database","location","initialization","change-detection"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}