Tree fetch 404 toast on repos whose backend is healthy #203
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#203
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Opening some repos shows "not found: " toast on the tree fetch
Opening repos (e.g.
o/r) shows an error toast with keySHA:<sha>:TREE:(empty path) and bodynot found: <sha>, where<sha>is the repo's CURRENT head sha.Evidence gathered (could not reproduce server-side — backend is healthy)
GET /o/r/api→ 200, head2dd90b80…(same sha as the toast), on BOTH127.0.0.1:8080andhttps://hub.packden.us.GET /o/r/api/tree/mainand/o/r/api/tree/<full-sha>→ 200 on both lanes, both hosts.web/src/lib/data.js:339(sha:<sha>:tree:<path>, CSS-uppercased in the tray chip); SDK builds/tree/{rev}[/{path}]correctly.not found: <sha>(nearest:tree %s:%s not foundinbind_wal.go:301,repository not found:inwal/types.go,object not found:in store).Cache-Control: private, max-age=31536000, immutable— a poisoned disk-cache entry replays failures (the #41 pattern); the stack was recreated ~10× today, giving ample windows for transient failures to get cached.Fix
Reproduce LIVE in a browser (open the repo, watch the network tab): capture the actual failing request (URL, status, body, served-from-cache?) and fix the real cause. Prime suspects, in order: (1) poisoned immutable-cache entry replaying a transient failure (fix: no-store/error-path cache discipline on sha-addressed GETs, cache-busting or entry invalidation); (2) a resolve-then-fetch race serving a sha the tree path can't see; (3) proxy/host-specific path mangling on hub.packden.us. Do NOT "fix" by hiding the toast — the fetch genuinely fails in the user's browser.
Acceptance criteria
node --testgreen (+ Go gates if backend touched).Root cause found and fixed in PR #204 (branch fix/issue-203, not merged).
It is NOT cache poisoning — every failing request goes to the network and the 404s carry no Cache-Control. Captured live via CDP on a cold server:
GET /acme/demo/api/tree/8de1c9a5…→ 404not found: 8de1c9a5…(51 bytes, fromDiskCache=false) whileGET …/api/resolve→ 200 with the same sha andGET …/api/tree/main→ 200 (and healed the copy).Mechanism: on a cold serving copy (fresh restart/recreate — refs synced, objects/pack empty), the tree handler re-resolves the full head sha via
git rev-parsein the empty copy → miss → 404 from the Resolve fallback arm (bind_wal.go, via notFoundOr). The UI's resolve→sha flow never issues a ref-named request, so nothing ever triggers the serve sync that would materialize the packs — every visit re-toasts. That is also why your curls looked healthy:tree/mainheals,tree/<sha>does not.Fix: Resolve serve-syncs once and retries rev-parse on a full-sha miss before 404ing. Post-fix browser proof on a cold server: clean open, tree renders, no toast, zero console errors, both themes.
PR #204 review (scratch worktree /tmp/pr204 @
2ba62a1; main worktree untouched, no browser re-drive per instructions — relying on author's CDP capture in #203 comment-1763):PASS law 6 / hot path: retry in internal/api/bind_wal.go:213 is gated on
sha == '' && revIsFullSHA(segs[0])— ref-named hits return at :194-205 before rev-parse, sha hits return with sha != '' so the block is unreachable. Zero added store round trips on hit. The extra Sync(Serve) runs only on the failure path (doc-allowed).PASS bounded: sync-once-then-retry-once, no loop. Sync error swallowed to fall through to the original 404 (:222,
if serr == nil); revParse never returns non-nil err (recipes.go:51-57 returns '',nil on miss) so no error-masking path. No retry storm possible.PASS 404 shape: genuine misses keep exact
not found: <seg>at both Resolve and HTTP layers — asserted in TestWalResolveColdCopyRetriesServe case 1 (bind_wal_test.go).PASS concurrency: walView holds no locks across the call; engine.Sync owns syncMu/packMu per doc 05 §5.2 (comment cites it). Two concurrent cold resolves may duplicate the serve materialize — idempotent, acceptable; open path itself is single-flight (wal/registry.go:28).
PASS imports: no new imports (body-only change; import block unchanged).
PASS gates (scratch worktree): gofmt clean, go vet clean, go test -race ./internal/api/ PASS incl. new TestWalResolveColdCopyRetriesServe, package coverage 95.4% >= 95% gate.
PASS docs: 07_api.md §9.3 step-3 + Decisions entries accurately describe the behavior (full-sha-only, once, hot path unchanged, exact 404 shape, live CDP proof ruling out cache poisoning).
PASS #205 out of scope: push-path pack- manifest checksums (write path) vs this read-path Resolve retry (local-fixture test, no manifest involvement) — genuinely separate, not load-bearing.
No fixes pushed — nothing to fix. MERGE RECOMMENDATION: ready to merge.
Fixed by PR #204 (review: hot path zero-cost, bounded retry, 404 shape preserved; 95.4% coverage), merged. Closing.