helix-editor/helix · warning · anyhow::Error

no diff provider returns success

Error message

no diff provider returns success

What it means

DiffProviderRegistry::for_each_changed_file runs every configured provider (git is the only built-in one) and uses find_map on their results. If no provider returned Ok — in practice, because gix failed to discover or open a repository for the cwd ('failed to discover git repo' when the directory is not inside any git repository, or an open/status failure on a corrupt .git) — the fallback callback is invoked with Err('no diff provider returns success'). Consumers surface it via status::report_blocking, e.g. the changed-files picker shows it in the statusline.

Source

Thrown at helix-vcs/src/lib.rs:79

        })
    }

    /// Fire-and-forget changed file iteration. Runs everything in a background task. Keeps
    /// iteration until `on_change` returns `false`.
    pub fn for_each_changed_file(
        self,
        cwd: PathBuf,
        trust_full: bool,
        f: impl Fn(Result<FileChange>) -> bool + Send + 'static,
    ) {
        tokio::task::spawn_blocking(move || {
            if self
                .providers
                .iter()
                .find_map(|provider| provider.for_each_changed_file(&cwd, trust_full, &f).ok())
                .is_none()
            {
                f(Err(anyhow!("no diff provider returns success")));
            }
        });
    }
}

impl Default for DiffProviderRegistry {
    fn default() -> Self {
        // currently only git is supported
        // TODO make this configurable when more providers are added
        let providers = vec![
            #[cfg(feature = "git")]
            DiffProvider::Git,
            DiffProvider::None,
        ];
        DiffProviderRegistry { providers }
    }
}

View on GitHub (pinned to 079a789e8c)

Solutions

  1. If the project is not under git, initialize or ignore the message — the picker just has nothing to list.
  2. Verify `git status` runs cleanly in the same directory from a terminal; if it errors, repair the repository (e.g. `git fsck`, restore .git/config).
  3. For non-git projects wanting picker parity, put the project under git (git init) or accept the empty picker.
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: is the cwd inside a git repo at all?
let in_repo = gix::discover::upward_opts(
    &cwd,
    gix::discover::upwards::Options { dot_git_only: true, ..Default::default() },
).is_ok();
if !in_repo { /* skip the changed-files picker / expect the fallback error */ }

Try / catch

// the registry already funnels every provider failure into one Err callback
cx.editor.diff_providers.clone().for_each_changed_file(cwd, trust, move |res| match res {
    Ok(change) => injector.push(change).is_ok(),
    Err(err) => { status::report_blocking(err); true } // degrade gracefully: empty picker
});

Prevention

When it happens

Trigger: Opening the changed-files picker (default `space` g) in a directory that is not inside any git repository; a corrupted/unreadable .git directory; a repo gix cannot open due to discovery errors.

Common situations: Using helix on non-git projects (the most common case — no VCS integration is configured for them); broken .git dirs after interrupted operations; repos with unreadable config.

Related errors


AI-assisted analysis of helix-editor/helix@079a789e8c (2026-08-16). Data as JSON: /api/errors/02d10a7a14b9286a. Report an issue: GitHub.