diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs
index 579811df..18af13ae 100644
--- a/helix-dap/src/client.rs
+++ b/helix-dap/src/client.rs
@@ -113,7 +113,7 @@ impl Client {
         id: usize,
     ) -> Result<(Self, UnboundedReceiver<Payload>)> {
         // Resolve path to the binary
-        let cmd = helix_stdx::env::which(cmd).map_err(|err| anyhow::anyhow!(err))?;
+        let cmd = helix_stdx::env::which(cmd)?;
 
         let process = Command::new(cmd)
             .args(args)
diff --git a/helix-dap/src/lib.rs b/helix-dap/src/lib.rs
index 21162cb8..d0229249 100644
--- a/helix-dap/src/lib.rs
+++ b/helix-dap/src/lib.rs
@@ -19,6 +19,8 @@ pub enum Error {
     #[error("server closed the stream")]
     StreamClosed,
     #[error(transparent)]
+    ExecutableNotFound(#[from] helix_stdx::env::ExecutableNotFoundError),
+    #[error(transparent)]
     Other(#[from] anyhow::Error),
 }
 pub type Result<T> = core::result::Result<T, Error>;
diff --git a/helix-loader/src/grammar.rs b/helix-loader/src/grammar.rs
index 537e1282..7977c6df 100644
--- a/helix-loader/src/grammar.rs
+++ b/helix-loader/src/grammar.rs
@@ -86,10 +86,8 @@ pub fn get_language(name: &str) -> Result<Language> {
 }
 
 fn ensure_git_is_available() -> Result<()> {
-    match helix_stdx::env::which("git") {
-        Ok(_cmd) => Ok(()),
-        Err(err) => Err(anyhow::anyhow!("'git' could not be found ({err})")),
-    }
+    helix_stdx::env::which("git")?;
+    Ok(())
 }
 
 pub fn fetch_grammars() -> Result<()> {
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index f8c2912e..fb32f6eb 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -183,7 +183,7 @@ impl Client {
         doc_path: Option<&std::path::PathBuf>,
     ) -> Result<(Self, UnboundedReceiver<(usize, Call)>, Arc<Notify>)> {
         // Resolve path to the binary
-        let cmd = helix_stdx::env::which(cmd).map_err(|err| anyhow::anyhow!(err))?;
+        let cmd = helix_stdx::env::which(cmd)?;
 
         let process = Command::new(cmd)
             .envs(server_environment)
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index c99ec217..53b2712d 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -44,6 +44,8 @@ pub enum Error {
     #[error("Unhandled")]
     Unhandled,
     #[error(transparent)]
+    ExecutableNotFound(#[from] helix_stdx::env::ExecutableNotFoundError),
+    #[error(transparent)]
     Other(#[from] anyhow::Error),
 }
 
diff --git a/helix-stdx/src/env.rs b/helix-stdx/src/env.rs
index 3676727f..90a0aee8 100644
--- a/helix-stdx/src/env.rs
+++ b/helix-stdx/src/env.rs
@@ -1,6 +1,5 @@
-pub use which::which;
-
 use std::{
+    ffi::OsStr,
     path::{Path, PathBuf},
     sync::RwLock,
 };
@@ -36,10 +35,33 @@ pub fn env_var_is_set(env_var_name: &str) -> bool {
     std::env::var_os(env_var_name).is_some()
 }
 
-pub fn binary_exists(binary_name: &str) -> bool {
+pub fn binary_exists<T: AsRef<OsStr>>(binary_name: T) -> bool {
     which::which(binary_name).is_ok()
 }
 
+pub fn which<T: AsRef<OsStr>>(
+    binary_name: T,
+) -> Result<std::path::PathBuf, ExecutableNotFoundError> {
+    which::which(binary_name.as_ref()).map_err(|err| ExecutableNotFoundError {
+        command: binary_name.as_ref().to_string_lossy().into_owned(),
+        inner: err,
+    })
+}
+
+#[derive(Debug)]
+pub struct ExecutableNotFoundError {
+    command: String,
+    inner: which::Error,
+}
+
+impl std::fmt::Display for ExecutableNotFoundError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "command '{}' not found: {}", self.command, self.inner)
+    }
+}
+
+impl std::error::Error for ExecutableNotFoundError {}
+
 #[cfg(test)]
 mod tests {
     use super::{current_working_dir, set_current_working_dir};