spacedriveapp/spacedrive · error
PersistentEventHandler not connected to FsWatcherService
Error message
PersistentEventHandler not connected to FsWatcherService
What it means
PersistentEventHandler::start mirrors the ephemeral handler: after the double-start guard it clones the FsWatcherService from RwLock<Option<...>> and errors when None. The comment in the source notes locations can be registered before start(); the same leniency does not apply to the watcher itself, which must already be connected when start runs.
Source
Thrown at core/src/ops/indexing/handlers/persistent.rs:222
Ok(())
}
/// Get all registered locations
pub async fn locations(&self) -> Vec<LocationMeta> {
self.locations.read().await.values().cloned().collect()
}
/// Start the event handler
pub async fn start(&self) -> Result<()> {
if self.is_running.swap(true, Ordering::SeqCst) {
warn!("PersistentEventHandler is already running");
return Ok(());
}
let fs_watcher = self.fs_watcher.read().await.clone();
let Some(fs_watcher) = fs_watcher else {
return Err(anyhow::anyhow!(
"PersistentEventHandler not connected to FsWatcherService"
));
};
debug!("Starting PersistentEventHandler");
// Create workers for all registered locations AND register paths with FsWatcher
// This is critical: locations may have been added before start() was called,
// when the FsWatcher wasn't connected yet, so we need to register them now.
let locations: Vec<LocationMeta> = self.locations.read().await.values().cloned().collect();
for meta in &locations {
self.ensure_worker(meta.clone()).await?;
// Register the path with the OS-level watcher (may have been skipped during add_location)
debug!(
"Registering path {} with FsWatcher for location {}",
meta.root_path.display(),
meta.idView on GitHub (pinned to 6dfeccf211)
Solutions
- Attach the FsWatcherService before calling start() on the persistent handler
- Verify watcher service initialization succeeded in daemon startup logs before handlers start
- If watcher-less operation is intended, downgrade to a warning and skip subscription
Defensive patterns
Strategy: validation
Validate before calling
// Check the watcher slot before start
if handler.fs_watcher_slot_filled().await {
handler.start().await?;
} else {
tracing::warn!("PersistentEventHandler not wired to a watcher; skipping start");
} Try / catch
if let Err(e) = persistent_handler.start().await {
if e.to_string().contains("not connected to FsWatcherService") {
// connect the watcher, then retry start() once
}
} Prevention
- Register locations after the watcher is connected, or rely on start()'s re-registration pass
- Verify watcher service initialization in startup logs before handlers run
- Downgrade to a warn-and-skip when watcher-less operation is an accepted mode
When it happens
Trigger: Calling start() on a PersistentEventHandler whose fs_watcher slot was never populated; watcher service failed to initialize during daemon startup; handler started after the watcher was dropped during shutdown.
Common situations: Daemon startup ordering bugs; feature-flagged watcher disabled but handlers still started; tests constructing the handler directly without a watcher.
Related errors
- EphemeralEventHandler not connected to FsWatcherService
- Library not found: {}
- Location not found: {}
- Failed to get metadata via backend: {}
- Location {} has no root entry
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/28d84231e28bc07b.
Report an issue: GitHub.