The Storer interface documents that Get and Stat return storage.ErrNotFound for a missing object. The file and rclone
backends honor this; the s3 backend did not. S3Storer.Get and Stat
returned the raw AWS SDK error, so errors.Is(err, storage.ErrNotFound)
was false on s3 and any caller branching on ErrNotFound behaved
differently depending on the backend.
Both methods now wrap ErrNotFound when the SDK reports a missing
object, and leave every other error untouched. The not-found detection
lives in a small exported s3.IsNotFound helper in internal/s3, which HeadObject also now uses, so the SDK's two missing-object error types
(NoSuchKey from Get, NotFound from Head/Stat) have one definition
instead of two copies.
Tripwire for the reader: the mapping stays in the storage layer, not
in internal/s3, because internal/s3 must not import storage
(storage imports it). The new test spins up an in-process gofakes3
server and asserts a missing key maps to ErrNotFound through the real
client; it fails without the mapping (Get surfaces NoSuchKey, Stat NotFound).
The issue notes a TestS3StorerMissingKeyDivergence from the #66 tests; that test is not on next, so this adds its own directly-asserting test rather than
tightening one that isn't here.
model: claude-opus-4-8
Fixes https://git.eeqj.de/sneak/vaultik/issues/129.
The `Storer` interface documents that `Get` and `Stat` return
`storage.ErrNotFound` for a missing object. The `file` and `rclone`
backends honor this; the s3 backend did not. `S3Storer.Get` and `Stat`
returned the raw AWS SDK error, so `errors.Is(err, storage.ErrNotFound)`
was false on s3 and any caller branching on `ErrNotFound` behaved
differently depending on the backend.
Both methods now wrap `ErrNotFound` when the SDK reports a missing
object, and leave every other error untouched. The not-found detection
lives in a small exported `s3.IsNotFound` helper in `internal/s3`, which
`HeadObject` also now uses, so the SDK's two missing-object error types
(`NoSuchKey` from Get, `NotFound` from Head/Stat) have one definition
instead of two copies.
Tripwire for the reader: the mapping stays in the `storage` layer, not
in `internal/s3`, because `internal/s3` must not import `storage`
(`storage` imports it). The new test spins up an in-process gofakes3
server and asserts a missing key maps to `ErrNotFound` through the real
client; it fails without the mapping (Get surfaces `NoSuchKey`, Stat
`NotFound`).
The issue notes a `TestS3StorerMissingKeyDivergence` from the
https://git.eeqj.de/sneak/vaultik/issues/66 tests; that test is not on
`next`, so this adds its own directly-asserting test rather than
tightening one that isn't here.
model: claude-opus-4-8
S3Storer.Get and Stat returned the raw AWS SDK error for a missing
object, so errors.Is(err, storage.ErrNotFound) was false on the s3
backend while the file and rclone backends honored the Storer contract.
Callers that branch on ErrNotFound behaved differently per backend.
Both now wrap ErrNotFound when the SDK reports a missing object,
leaving every other error intact. The not-found detection is a small
exported s3.IsNotFound helper, also used by HeadObject so the two share
one definition. A test asserts a missing key maps to ErrNotFound on the
s3 backend; it fails without the mapping.
model: claude-opus-4-8
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #129.
The
Storerinterface documents thatGetandStatreturnstorage.ErrNotFoundfor a missing object. Thefileandrclonebackends honor this; the s3 backend did not.
S3Storer.GetandStatreturned the raw AWS SDK error, so
errors.Is(err, storage.ErrNotFound)was false on s3 and any caller branching on
ErrNotFoundbehaveddifferently depending on the backend.
Both methods now wrap
ErrNotFoundwhen the SDK reports a missingobject, and leave every other error untouched. The not-found detection
lives in a small exported
s3.IsNotFoundhelper ininternal/s3, whichHeadObjectalso now uses, so the SDK's two missing-object error types(
NoSuchKeyfrom Get,NotFoundfrom Head/Stat) have one definitioninstead of two copies.
Tripwire for the reader: the mapping stays in the
storagelayer, notin
internal/s3, becauseinternal/s3must not importstorage(
storageimports it). The new test spins up an in-process gofakes3server and asserts a missing key maps to
ErrNotFoundthrough the realclient; it fails without the mapping (Get surfaces
NoSuchKey, StatNotFound).The issue notes a
TestS3StorerMissingKeyDivergencefrom the#66 tests; that test is not on
next, so this adds its own directly-asserting test rather thantightening one that isn't here.
model: claude-opus-4-8
PASS
model: claude-opus-4-8