spacedriveapp/spacedrive · error

EphemeralEventHandler not connected to FsWatcherService

Error message

EphemeralEventHandler not connected to FsWatcherService

What it means

EphemeralEventHandler::start guards against double-start with an atomic flag, then clones the FsWatcherService from an RwLock<Option<...>>. If that slot is None, the handler has no event bus to subscribe to and start() returns this error: the handler was constructed without (or before) being connected to the watcher service.

Source

Thrown at core/src/ops/indexing/handlers/ephemeral.rs:79

	/// Connect to a FsWatcherService
	pub async fn connect(&self, fs_watcher: Arc<FsWatcherService>) {
		*self.fs_watcher.write().await = Some(fs_watcher);
	}

	/// Start the event handler
	///
	/// Spawns a task that subscribes to filesystem events and routes
	/// matching events to the ephemeral responder.
	pub async fn start(&self) -> Result<()> {
		if self.is_running.swap(true, Ordering::SeqCst) {
			warn!("EphemeralEventHandler 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!(
				"EphemeralEventHandler not connected to FsWatcherService"
			));
		};

		debug!("Starting EphemeralEventHandler");

		let mut rx = fs_watcher.subscribe();
		let context = self.context.clone();
		let rule_toggles = self.rule_toggles;
		let is_running = self.is_running.clone();

		tokio::spawn(async move {
			debug!("EphemeralEventHandler task started");

			while is_running.load(Ordering::SeqCst) {
				match rx.recv().await {
					Ok(event) => {
						if let Err(e) = Self::handle_event(&context, &event, rule_toggles).await {

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Connect the FsWatcherService to the handler before calling start()
  2. Make daemon startup order explicit: construct watcher → attach handlers → start handlers
  3. If running without a watcher is legitimate for your deployment, return Ok(()) with a warn instead of erroring

Example fix

// before
let Some(fs_watcher) = fs_watcher else {
    return Err(anyhow::anyhow!("EphemeralEventHandler not connected to FsWatcherService"));
};

// after: fail fast at wiring time, not at start time
let Some(fs_watcher) = fs_watcher else {
    warn!("EphemeralEventHandler start skipped: no FsWatcherService connected");
    return Ok(());
};
Defensive patterns

Strategy: validation

Validate before calling

// Verify wiring before starting
if self.fs_watcher.read().await.is_none() {
    tracing::warn!("EphemeralEventHandler has no FsWatcherService; not starting");
    return Ok(());
}
self.start().await?;

Try / catch

if let Err(e) = handler.start().await {
    if e.to_string().contains("not connected to FsWatcherService") {
        // fix wiring order: connect watcher first, then call start() again
    }
}

Prevention

When it happens

Trigger: Calling start() before a FsWatcherService was set via the handler's connect/setter; watcher construction failed earlier and the None placeholder remained; start() invoked during daemon teardown after the watcher was taken out.

Common situations: Wiring order bugs in daemon startup (start before connect); test harnesses building the handler without a real watcher; watcher service disabled in configuration.

Related errors


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