Plugin marketplace GCS tarball sync strips execute permissions from .sh files

Resolved 💬 2 comments Opened Mar 26, 2026 by mattheworiordan Closed Mar 27, 2026

Summary

The GCS-based marketplace plugin sync mechanism extracts tarballs without preserving execute permissions on .sh files, causing "Permission denied" errors for any plugin that uses shell script hooks.

Reproduction

Environment: macOS (Darwin 25.2.0), Claude Code with multiple profiles (~/.claude/ and ~/.claude-personal/)

Steps:

  1. Install a plugin with shell script hooks (e.g., ralph-loop which has hooks/stop-hook.sh)
  2. Wait for the marketplace to sync via the GCS tarball path
  3. Observe that .sh files are written with 644 permissions (no execute bit)
  4. Any hook execution fails with: Permission denied

Error message:

Stop hook error: Failed with non-blocking status code: /bin/sh: /Users/<user>/.claude-personal/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop/hooks/stop-hook.sh: Permission denied

Root Cause Analysis

There are two sync paths for marketplace plugins configured with {"source": "github", "repo": "anthropics/claude-plugins-official"}:

  1. Git clone/pull — preserves file permissions correctly (files get 755)
  2. GCS tarball download — extracts files with 644, stripping the execute bit

Evidence from the same machine, same repo, same known_marketplaces.json config:

| Profile | Sync method | .sh permissions | .git dir present | Last synced |
|---------|-------------|-------------------|--------------------|-------------|
| Work (~/.claude/) | Git clone | 755 (correct) | Yes | Jan 26 |
| Personal (~/.claude-personal/) | GCS tarball | 644 (broken) | No | Mar 26 (multiple times daily) |

The personal profile has a .gcs-sha file instead of a .git directory, and all files share the same timestamp (consistent with bulk tarball extraction). Every .sh file in the personal profile's marketplace directory is 644 — this is not specific to one plugin.

The plugin cache directory (plugins/cache/claude-plugins-official/ralph-loop/unknown/) also has 644 permissions on .sh files, while older SHA-named cache entries have correct 755 permissions (suggesting they were created via the git path).

Impact

  • Every plugin with .sh hooks is broken on profiles using the GCS sync path
  • chmod +x fixes are temporary — the next sync cycle (which happens multiple times daily) overwrites with 644 again
  • This has been manually fixed 3 times in 2 days before identifying the root cause
  • The error fires silently on every stop hook invocation (~57 times across 10 conversations in 2 days)

Expected Behavior

The GCS tarball extraction should either:

  1. Preserve execute permissions from the tarball (if they're stored correctly)
  2. Apply +x to all .sh files after extraction
  3. Or respect the file permissions that the git-clone path correctly handles

Workaround

None that persists. Converting the marketplace directory to a git clone may work temporarily but risks being overwritten by the GCS sync.

🤖 Generated with Claude Code

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗