gitbutlerapp/gitbutler · error

file monitor stopped

Error message

file monitor stopped

What it means

FileMonitorHandle::flush sends a Flush command over a channel to the monitor worker thread. If the send fails, the receiver has been dropped, meaning the monitor thread has exited/shut down and can no longer emit pending events. The error is a channel-closed surrogate for 'monitor is dead'.

Solutions

  1. Check whether the monitor was shut down before calling flush; keep the monitor alive for the handle's lifetime.
  2. Treat this error as benign during shutdown and ignore/log it.
  3. Recreate the file monitor if continued watching is needed.
  4. Check logs for an earlier monitor-thread panic (e.g. watch setup failure) that caused the exit.

Example fix

// before
handle.flush()?; // Err even if you just want pending events
// after
if let Err(e) = handle.flush() {
    tracing::warn!("file monitor unavailable: {e}"); // benign at shutdown
}
Defensive patterns

Strategy: fallback

Try / catch

match handle.flush() {
    Ok(()) => {},
    Err(e) => log::warn!("file monitor stopped, skipping flush: {e}"), // benign during shutdown
}

Prevention

When it happens

Trigger: Calling flush() after the file monitor was stopped or its worker thread panicked/exited; flushing during app shutdown after cmd_tx's receiver was dropped.

Common situations: Calling flush on a handle whose monitor was dropped; race between shutdown and a UI/editor action requesting a flush; watch teardown due to a fatal watch error earlier.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/145c16b05e2f2f6b. Report an issue: GitHub.

Appendix: source

Thrown at crates/gitbutler-filemonitor/src/file_monitor.rs:62

const FLUSH_AFTER_EMPTY: u32 = 3;

enum Command {
    Flush,
}

/// Handle for a running file monitor spawned with [`spawn()`].
///
/// Dropping this handle will stop the monitor as soon as it tries to send the next event, failing as there is no receiver.
pub struct FileMonitorHandle {
    cmd_tx: std::sync::mpsc::Sender<Command>,
}

impl FileMonitorHandle {
    /// Request that pending filesystem events are emitted immediately.
    pub fn flush(&self) -> Result<()> {
        self.cmd_tx
            .send(Command::Flush)
            .map_err(|_| anyhow!("file monitor stopped"))
    }
}

const ENV_WATCH_MODE: &str = "GITBUTLER_WATCH_MODE";

/// Control how the filesystem watch should be established.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum WatchMode {
    /// Recursively watch the worktree (and an extra git-dir if the repo uses
    /// a linked worktree with a git-dir outside the worktree), using [`notify::RecursiveMode::Recursive`].
    Legacy,
    /// Ignore-aware watch plan: non-recursive watches of non-ignored worktree directories,
    /// plus explicit git-dir watches and dynamic watch additions for newly created directories.
    /// Each directory is watched with [`notify::RecursiveMode::NonRecursive`].
    Modern,
    /// Automatically pick a mode based on platform heuristics.
    ///
    #[default]

View on GitHub (pinned to 58e5313667)