Skip to content

Fix attachment download error mapping and Content-Type resolution; add GC endpoint - #68

Merged
cuibonobo merged 2 commits into
mainfrom
claude/attachment-issues-plan-cwjtpq
Aug 20, 2026
Merged

Fix attachment download error mapping and Content-Type resolution; add GC endpoint#68
cuibonobo merged 2 commits into
mainfrom
claude/attachment-issues-plan-cwjtpq

Conversation

@cuibonobo

@cuibonobo cuibonobo commented Aug 19, 2026

Copy link
Copy Markdown
Member

Summary

Addresses the five attachment-related issues (#52, #37, #46, #48, #38):

Incidental dependency fix

Bumps @haverstack/adapter-local to 0.9.0. While fixing #48 I removed a blanket catch that had been silently absorbing every non-permission error as a hardcoded 404 — with it gone, a genuinely-missing attachment started 500ing instead of 404ing. Root cause: the resolved @haverstack/blob-adapter-disk@0.7.0 (transitive via adapter-local@0.8.0) still depended on @haverstack/core@^0.9.0 while the rest of the tree was on 0.10.0, so DiskBlobAdapter's StackNotFoundError was a different class than the one @haverstack/wire-types' serializeError checks for, and instanceof silently failed.

This went through two states: an earlier commit on this branch pinned blob-adapter-disk to ^0.8.0 via a pnpm.overrides workaround, since adapter-local@0.8.0's own declared range (^0.7.0) excluded the fixed version. adapter-local@0.9.0 has since been published upstream with the corrected blob-adapter-disk: ^0.8.0 dependency, so this PR now just bumps the real dependency and the override is gone.

Test plan

🤖 Generated with Claude Code

https://claude.ai/code/session_012GdVbbu2KmZkfcvRmY4BRq

claude added 2 commits August 19, 2026 21:01
…ent-Type, add GC endpoint

Fixes #48: GET /attachments/:fileId no longer collapses every
authenticated denial to 401 or masks unexpected errors as 404. Only an
anonymous StackPermissionError becomes 401 now; a verified-but-denied
requester gets 403, StackNotFoundError still maps to 404, and anything
else propagates to the global error handler and is logged. Missing and
inaccessible files stay indistinguishable for non-owners, per the
anti-oracle rule core already enforces.

Fixes #37: the download route now resolves Content-Type from all three
spec'd sources instead of two — ?contentType, then ?filename extension
inference, then (newly) the fileId's first-recorded _attachment@1
metadata record — via core's resolveAttachmentDownloadContentType(),
replacing the local deny-list/extension-table with core's safe-list.
Content-Disposition's filename now prefers the requester's own record,
falling back to the first-recorded one.

Fixes #38: adds owner-only POST /attachments/gc, wired to
ScopedStack.collectAttachmentGarbage(), accepting optional
{ graceMs, dryRun } and returning { deleted, reclaimedBytes }.

Closes #46 (already landed alongside #52's atomic-upload fix; this
commit doesn't touch upload) and #52 (no action; already closed).

Also pins @haverstack/blob-adapter-disk to ^0.8.0 via a pnpm override.
The resolved 0.7.0 depended on @haverstack/core@^0.9.0 while the rest
of the tree is on 0.10.0, so DiskBlobAdapter's StackNotFoundError was a
different class than the one @haverstack/wire-types checks for —
instanceof failed silently and a missing attachment 500'd instead of
404ing. The old blanket catch-all in this route masked it; removing
that catch-all for #48 exposed it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GdVbbu2KmZkfcvRmY4BRq
adapter-local@0.9.0 now declares blob-adapter-disk@^0.8.0 directly (the
range gap fixed upstream), so the pnpm.overrides workaround from the
previous commit is no longer needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GdVbbu2KmZkfcvRmY4BRq
@cuibonobo
cuibonobo merged commit 5ba3116 into main Aug 20, 2026
4 checks passed
@cuibonobo
cuibonobo deleted the claude/attachment-issues-plan-cwjtpq branch August 20, 2026 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants