[BUG] claude plugin update leaves gitCommitSha stale for url-source marketplace entries
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 44c9b2d6e889982ac18c27d05a19fefe335194e1 → b36e0829c6d0140e93cfef2ca599b1b07d4a7797, 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
- Install a plugin whose marketplace entry uses a url source with an explicit SHA.
superpowers@claude-plugins-officialis one:
``json``
{
"name": "superpowers",
"source": {
"source": "url",
"url": "https://github.com/obra/superpowers.git",
"sha": "<pinned sha>"
}
}
- Note the recorded SHA:
jq '.plugins["superpowers@claude-plugins-official"]' ~/.claude/plugins/installed_plugins.json - Wait for the marketplace to bump that entry's
source.sha(or point at a marketplace you control and bump it yourself), then runclaude plugin marketplace update <marketplace>. - Run
claude plugin update superpowers@claude-plugins-official. It reports a successful version change. - 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'sgitCommitShaalso 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,
cachePluginre-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)._
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗