[BUG] claude install creates broken symlink: %h not expanded in path

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 9 comments · opened Aug 3, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Broken symlink created by claude install

The claude install command (run by the official installer script) creates a broken symlink at ~/.local/bin/claude, pointing to:

%h/.local/share/claude/versions/<version>

instead of expanding %h to the actual home directory path.

The shell installer script (curl -fsSL https://claude.ai/install.sh) is correct — it downloads the binary and runs:

"$binary_path" install

The broken symlink is created by the binary's internal install subcommand.

Environment

  • OS: Fedora 44
  • Shell: bash
  • Claude Code: 2.1.220

Workaround

ln -sf ~/.local/share/claude/versions/2.1.220 ~/.local/bin/claude

What Should Happen?

Expected behavior

claude -> /home/user/.local/share/claude/versions/2.1.220

Error Messages/Logs

## Actual behavior


file ~/.local/bin/claude


Output:


/home/user/.local/bin/claude: broken symbolic link to %h/.local/share/claude/versions/2.1.220

Steps to Reproduce

Steps to reproduce

curl -fsSL https://claude.ai/install.sh | bash

ls -la ~/.local/bin/claude
# claude -> %h/.local/share/claude/versions/2.1.220 (broken)

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.220

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗

2 Comments

KrypticKode007 · 27 days ago

#!/usr/bin/env bash
set -euo pipefail

INSTALL_ROOT="${HOME}/.local/share/claude/versions"
BIN_DIR="${HOME}/.local/bin"
LINK_PATH="${BIN_DIR}/claude"

info() {
printf '[info] %s
' "$1"
}

fail() {
printf '[fail] %s
' "$1" >&2
exit 1
}

[ -d "$INSTALL_ROOT" ] || fail "Install root not found: $INSTALL_ROOT"
mkdir -p "$BIN_DIR"

LATEST_VERSION="$({
find "$INSTALL_ROOT" -mindepth 1 -maxdepth 1 ( -type d -o -type f -o -type l ) -printf '%f
' 2>/dev/null || true
} | sort -V | tail -n 1)"

[ -n "$LATEST_VERSION" ] || fail "No installed Claude versions found in: $INSTALL_ROOT"

TARGET_PATH="${INSTALL_ROOT}/${LATEST_VERSION}"
[ -e "$TARGET_PATH" ] || [ -L "$TARGET_PATH" ] || fail "Target does not exist: $TARGET_PATH"

rm -f "$LINK_PATH"
ln -s "$TARGET_PATH" "$LINK_PATH"

info "Created symlink: $LINK_PATH -> $TARGET_PATH"

kacperpaczos · 27 days ago

The issue is intermittent — the symlink doesn't break every time Claude is launched. Here's what I observed:

  • Running claude (interactive TUI) does not always break the symlink
  • The symlink was recreated with the %h bug after an auto-update check (based on .last-update-result.json timestamps)
  • The breakage seems to happen specifically during the auto-update flow, not on every launch
  • When it does break, it persists until manually fixed — and gets re-broken by the next update check

Reproduction hint: It might be related to the auto-update check running in a context where $HOME or the path resolution doesn't work as expected. The binary's internal install subcommand is what creates the broken symlink with literal %h instead of the resolved home path.

Temporary workaround:
ln -sf ~/.local/share/claude/versions/$(ls ~/.local/share/claude/versions/ | sort -V | tail -1) ~/.local/bin/claude

Showing cached comments. Read the full discussion on GitHub ↗