When Claude Code Can't Find Git (But Git Works Fine in Terminal)

I hit a frustrating edge case the other day: the Claude Code panel inside the Claude desktop app repeatedly popped up a modal asking me to install Git.

Claude Code's Install Git dialog

Git is required to run local sessions. Run xcode-select --install in Terminal to install the Command Line Tools, or download Git directly — or switch to a remote environment.

The catch? Git was already installed.

Running git --version in my terminal returned a valid version immediately. Claude Code ran seamlessly from the command line. It was only the desktop GUI app that refused to acknowledge Git’s existence.

Since I was running the macOS 27 beta, my immediate assumption was “beta bug.” That single assumption cost me an hour of rabbit holes. Here is the complete post-mortem, wrong turns included.

First Guess: Broken Command Line Tools

On macOS, /usr/bin/git isn’t actually the Git binary — it’s a shim launcher that forwards commands to whichever developer directory xcode-select currently points to. Major macOS upgrades frequently break or unset this pointer, making a stale Command Line Tools installation the textbook culprit whenever Git suddenly “disappears” after an OS update.

Because direct package updates for beta OS releases aren’t always immediately served via Software Update, I downloaded the .dmg directly from the Apple Developer Downloads page, installed it, and manually reset the developer directory:

sudo xcode-select -s /Library/Developer/CommandLineTools
git --version   # git version 2.54.0 (Apple Git-157)
clang --version # Apple clang version 21.0.0

Everything checked out in the CLI: git worked, clang worked.

Yet, after re-opening the desktop app, the dialog remained stubbornly present.

If Git is functioning in the shell but invisible to the GUI, the issue wasn’t Git itself — it was how the application resolves environment binaries.

Second Guess: The GUI PATH Environment

This is a classic macOS tripwire. Apps launched from Finder, Dock, or Spotlight do not inherit environment variables or custom PATH definitions set in your shell startup scripts (.zshrc or .bash_profile). GUI applications launch inside a minimalist launchd context. A binary easily resolved by your shell can be completely invisible to a GUI app.

Furthermore, Claude’s desktop app caches its environment at startup. If you fix a path issue while the app is active, the app’s view of the system remains stale until a hard restart (right-clicking the Dock icon → Quit, rather than merely closing the window).

I checked my system’s default launchd configuration:

launchctl getenv PATH
# (empty)

It returned empty. So I explicitly set a baseline PATH for launchd:

sudo launchctl config user path "/Library/Developer/CommandLineTools/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"

After a full system reboot, launchctl getenv PATH verified the updated environment. I relaunched Claude Desktop, fully expecting victory.

The exact same dialog appeared.

At this point, I had diagnosed and fixed two legitimate system issues — a broken CLI tools pointer and a sparse GUI environment. Both were worth fixing, yet neither addressed the root cause.

I stopped guessing and went digging through actual process logs. Checking GitHub issue (#54754) for this exact behavior revealed the underlying failure mode:

Failed to spawn /Users/xxx/bin/git: spawn /Users/xxx/bin/git EACCES

The app wasn’t failing to find Git — it was finding a broken Git entry first in the system execution order and failing with an EACCES (Permission Denied) error when trying to execute it.

When a desktop app spawns a subprocess, it attempts to execute the very first match it discovers in the resolution path. If that candidate fails or lacks execution permissions, the process aborts immediately rather than falling through to subsequent matches like an interactive shell might.

I ran a resolution check to see every registered git binary path:

which -a git
# /usr/local/bin/git
# /usr/bin/git

There it was: /usr/local/bin/git preceded the standard system path /usr/bin/git.

Inspecting that file revealed its origin:

ls -la /usr/local/bin/git
# lrwxr-xr-x  1 epona  admin  28 Feb  8  2022 /usr/local/bin/git -> ../Cellar/git/2.35.1/bin/git

It was a lingering symlink created in February 2022. It pointed to ../Cellar/git/2.35.1/, an artifact from an old Intel-based Homebrew installation that had been wiped years ago. (/usr/local is the legacy x86 Homebrew path; Apple Silicon Homebrew operates under /opt/homebrew).

Because the target path no longer existed, attempting to run this broken reference directly threw an error.

The resolution required a single cleanup command:

sudo rm /usr/local/bin/git

Verifying the active paths again:

which -a git
# /usr/bin/git

git --version
# git version 2.54.0 (Apple Git-157)

I force-quit the desktop application and relaunched it. The prompt disappeared completely.

Key Takeaways

  1. Shells mask broken paths; GUI apps don’t. Interactive shells can hide orphaned binaries depending on alias configurations and environment handling, but spawn-based application calls will fail hard on the first invalid entry they encounter.
  2. Use which -a, not just which. Running a basic which git only shows the active path, whereas which -a lists all instances across your environment in order of precedence — making shadowed or dead binaries instantly visible.
  3. Check the application error logs early. Fixing intermediate environment issues (like Command Line Tools or launchctl variables) felt productive, but reading the actual subprocess spawn log directly pinpointed the precise path failure within seconds.

If a GUI developer tool reports that a CLI binary is missing despite working perfectly in your terminal, run which -a <tool> — chances are, an old symlink is standing first in line.

Related
AI · Claude Code Building Lexio with Two Claudes: A Workflow That Actually Works

How I use Claude Projects for architecture decisions and Claude Code for implementation—keeping thinking and coding deliberately separate, with Lexio as a real-world example.

Mar 13, 2026
macOS Raycast setups that make me more productive

A few simple Raycast setups that have stuck in my daily workflow: smart text snippets, hyper key app toggles, quick terminal shortcuts, and clipboard history.

Nov 18, 2025
Claude Code · AI Switching from Claude to ChatGPT

I recently switched from Claude to ChatGPT—here’s why, and what I’ve learned along the way.

Sep 20, 2025
All posts