Repository navigation
Colocated index write leaves a stale gix cache-tree; external git add produces duplicateEntries #9711
Description
Activity
- added a commit that references this issue
on Jun 27, 2026 - added 2 commits that reference this issue
on Jun 27, 2026 - added 2 commits that reference this issue
on Aug 10, 2026 - added a commit that references this issue
on Aug 15, 2026 Disclosure: posted by an AI agent (Claude) on behalf of @petejm, who reviewed and approved this comment.
Agreed that both should not stay open. My suggestion is to close #8884 as the duplicate and let #9712 close this one, but the call is yours, and I want to be explicit about what I did and did not verify.
Why they look like the same bug: the corruption in #8884 is doubled subtree entries, with the same hash on both rows.
040000 tree c3a484a7a4c1d2e2c0f03311eb2a74e3c266a9df internal 040000 tree c3a484a7a4c1d2e2c0f03311eb2a74e3c266a9df internalThat is the signature this mechanism produces: git rebuilds the cache-tree, trusts a stale child
entry_count, and emits the subtree entry twice. A genericduplicateEntriesreport could be several different things, but doubled subtree rows with matching hashes is specific to this one.Why I would keep this issue rather than #8884: this one carries the deterministic reproducer, which trips at iteration 1 on stock jj, plus the mechanism write up. #8884 says "Exact steps are unknown" and has had no reporter activity since 2026-02-15. #9712 already carries
Fixes #9711, so this issue closes on merge either way.What I have not verified: whether the stale cache-tree was the only source of corruption in that repo. #8884 has no steps to reproduce, so I could not confirm it from the report itself. That is why #9712 links #8884 in the CHANGELOG rather than adding a
Fixes:trailer for it. If the symptom recurs on a build containing this fix, that would be a genuinely different cause and worth a fresh issue rather than reopening.If you would rather do it the other way round, closing this one as a duplicate of the older report, that works too. Tell me which you prefer and I will take care of it.
- marked Partially corrupt repo: "error in tree ... duplicateEntries: contains duplicate file entries" #8884 as a duplicate of this issue
on Aug 15, 2026 - added a commit that references this issue
on Aug 25, 2026 - added a commit that references this issue
on Aug 25, 2026 Disclosure: posted by an AI agent (Claude) on behalf of @petejm, who reviewed and approved this comment.
Closing this as fixed by #9712, which merged in 8ef9bee.
The commit carries a
Fixes #9711trailer, but the auto-close did not fire when it landed through the merge queue, so this stayed open. Closing it by hand.For anyone arriving here from #8884: the jj side fix is a
State::remove_tree()before the colocated index write, inupdate_intent_to_add_impl(). The gitoxide root cause is GitoxideLabs/gitoxide#2421, which was closed in July as documented rather than fixed, so the contract still stands: remove the tree cache before writing whenever entries changed. IfduplicateEntriesreappears on a build containing 8ef9bee, that is a different cause and worth a fresh issue rather than reopening this one.
Description
In a colocated jj+git repo, a
jjsnapshot writes.git/indexcarrying the git cache-tree (TREE extension) it loaded earlier, without invalidating it after mutating entries. The written index is self-inconsistent: a subtree node is marked valid but its cachedentry_countunder-counts the entries it spans.git write-treedirectly over that index is clean (git trusts a node marked valid). But a latergit addthat invalidates only the root — e.g. staging an unrelated sibling path, or a commit hook touching another dir — forces git to rebuild the cache-tree, trust the stale child count, and emit the same subtree entry twice →git fsckreportsduplicateEntriesand the push is rejected.Root cause: GitoxideLabs/gitoxide#2421 (gix doesn't invalidate the cache-tree on write); jj-side fix in the linked PR.
Steps to Reproduce the Problem
Deterministic by construction — it forces
git write-treeimmediately after the siblinggit add, removing the hook-timing dependence that made the original end-to-end path intermittent. Trips at iteration 1 on stock jj.Expected Behavior
After a
jjsnapshot,.git/indexis consistent: a later externalgit add+git write-treeproduces a valid tree, andgit fsckis clean.Actual Behavior
git fsckreportserror in tree <oid>: duplicateEntries: contains duplicate file entries; the rebuilt root tree lists the affected top-level directory twice with the same subtree oid. The push is rejected.Specifications
The mechanism is OS-independent — git's cache-tree rebuild (
cache-tree.c) and gix's TREE-extension serialization are not platform-specific; the deterministic repro above was run on macOS arm64.Possibly the same corruption reported in #8884, but via a different mechanism: #8884 theorizes jj's
tree_merge.rsmerge path; this is a colocated index-write defect and reproduces deterministically on 0.42. #8884's reporter was on 0.38 (untested here), so I can't rule out that they hit this same path — framing it as a distinct mechanism, not a different bug. Cross-ref gitoxide root cause: GitoxideLabs/gitoxide#2421