[BUG] claude plugin update leaves gitCommitSha stale for url-source marketplace entries

Status Open
Reported on v2.1.228
Maintainer reply None cached
Activity 1 comment · opened Aug 12, 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?

claude plugin update <plugin>@<marketplace> successfully updates a plugin whose marketplace entry uses source: "url", rewriting version, installPath, and lastUpdated in ~/.claude/plugins/installed_plugins.json — but leaves gitCommitSha at the value recorded when the plugin was first installed. The field then names a commit that is not the one on disk.

Concretely, updating superpowers@claude-plugins-official from 6.2.0 to 6.3.0: the marketplace pin moved 44c9b2d6e889982ac18c27d05a19fefe335194e1b36e0829c6d0140e93cfef2ca599b1b07d4a7797, the CLI reported success, and installPath now points at .../superpowers/6.3.0 — yet gitCommitSha still reads 3dcbd5c4b48e02263fbf4a3c01e3fe4f81d584d9, the SHA from the previous update.

This has now happened twice on the same entry. It was installed on 2026-07-24 at 11:04Z, correctly recording the then-current pin d884ae04edebef577e82ff7c4e143debd0bbec99 (v6.1.1). It was updated to 6.2.0 at 15:49Z the same day, after the marketplace pin moved to 3dcbd5c4 — and gitCommitSha stayed at d884ae04. That stale value was corrected by hand on 2026-08-08. Today's 6.2.0 → 6.3.0 update reproduced it, leaving the hand-written 3dcbd5c4 in place. The July occurrence was under an earlier CLI version, so this is not new to 2.1.228.

Per #83777, github-source plugins get a fresh SHA because cachePlugin re-clones independently, which would make this specific to url-source entries.

There is no impact on update resolution — version comparison is authoritative, and re-running the command correctly reports already at the latest version (6.3.0). The cost is provenance: for a url-source entry pinned by an explicit SHA, gitCommitSha is the only local record of which upstream commit is installed, and it silently misreports. Anything comparing it sees a stale value — including the tag-range up-to-date check, which returns up_to_date only when both resolvedVersion and gitCommitSha match.

What Should Happen?

After a successful update, gitCommitSha should record the commit actually installed (here, b36e0829c6d0140e93cfef2ca599b1b07d4a7797), or be removed if no SHA can be determined — rather than silently retaining a SHA from an earlier install.

Error Messages/Logs

$ claude plugin marketplace update claude-plugins-official
✔ Successfully updated marketplace: claude-plugins-official

$ claude plugin update superpowers@claude-plugins-official
Checking for updates for plugin "superpowers@claude-plugins-official" at user scope…
✔ Plugin "superpowers" updated from 6.2.0 to 6.3.0 for scope user. Restart to apply changes.

$ # ~/.claude/plugins/installed_plugins.json after the update:
    "superpowers@claude-plugins-official": [
      {
        "scope": "user",
        "installPath": "/home/glen/.claude/plugins/cache/claude-plugins-official/superpowers/6.3.0",
        "version": "6.3.0",
        "installedAt": "2026-07-24T11:04:55.392Z",
        "lastUpdated": "2026-08-12T18:19:01.362Z",
        "gitCommitSha": "3dcbd5c4b48e02263fbf4a3c01e3fe4f81d584d9"
      }
    ]

$ # expected gitCommitSha: b36e0829c6d0140e93cfef2ca599b1b07d4a7797
$ # (the marketplace's current pin for this entry, and the tree that was installed)

Steps to Reproduce

  1. Install a plugin whose marketplace entry uses a url source with an explicit SHA. superpowers@claude-plugins-official is one:

``json
{
"name": "superpowers",
"source": {
"source": "url",
"url": "https://github.com/obra/superpowers.git",
"sha": "<pinned sha>"
}
}
``

  1. Note the recorded SHA: jq '.plugins["superpowers@claude-plugins-official"]' ~/.claude/plugins/installed_plugins.json
  2. Wait for the marketplace to bump that entry's source.sha (or point at a marketplace you control and bump it yourself), then run claude plugin marketplace update <marketplace>.
  3. Run claude plugin update superpowers@claude-plugins-official. It reports a successful version change.
  4. Re-read installed_plugins.json.

Observed: version, installPath, and lastUpdated are all rewritten; gitCommitSha is unchanged from step 2.
Expected: gitCommitSha matches the marketplace entry's new source.sha.

I have not reproduced the github-source path myself; #83777's account of cachePlugin re-cloning is the basis for expecting it to differ.

Claude Model

Opus

Is this a regression?

I don't know

Claude Code Version

2.1.228 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Other — VS Code extension (anthropic.claude-code-2.1.228-linux-x64), native binary at resources/native-binary/claude

Additional Information

Likely cause. In the bundled 2.1.228 binary, the routine that rewrites an install record assigns the field only when the caller supplies a defined value, and never clears it:

if (c.lastUpdated = new Date().toISOString(), s !== undefined) c.gitCommitSha = s;

So a successful update that passes undefined leaves the previous value in place while every neighbouring field is rewritten. The install path derives the SHA as i?.sha ?? p.gitCommitSha ?? (m ? await Sei(f) : undefined), ending in a read of the fetched tree; the update path resolves only R?.sha ?? K.gitCommitSha, with no equivalent fallback. For a url-source entry neither term is populated, so undefined reaches the writer.

Identifiers above come from the minified bundle, so the call-site reasoning is inference — the writer line and the observed behaviour are direct.

Related, but distinct:

  • #79950 reports the same symptom ("installed_plugins.json's gitCommitSha also never updates") in the opposite scenario: the marketplace's declared version string never changes, so the update no-ops and nothing is written at all. Here the update ran and rewrote everything except this field.
  • #83777 diagnoses an adjacent problem in the same update path, and notes that "for remote (github) plugins, cachePlugin re-clones independently (so the SHA is fresh)" — matching the github-source behaviour above. It does not consider url-source entries, which is the gap this report covers.

_Drafted by Claude (Anthropic AI assistant)._

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗