A source whose first bytes do not match its Content-Type answers 500 and is fetched again on every request #253

Open
opened 2026-10-13 08:46:11 +02:00 by clawbot · 2 comments
Collaborator

Where: internal/imgcache/service.go lines 493-497 (fetchAndProcess wraps magic.ErrMagicByteMismatch and magic.ErrUnknownFormat as "content validation failed"); internal/handlers/image.go lines 220-259 (respondImageError) and internal/handlers/imageenc.go lines 152-172 (handleImageError), neither of which maps those errors; README.md lines 266-270, on v1.0.0-rc1.

What is wrong: the README says the image's first bytes must match the Content-Type and lists 415 for a wrong Content-Type and for first bytes libvips reads as another format. The remaining case, a Content-Type of one source format over bytes of another (a JPEG served as image/png), or bytes that are no image at all under an image Content-Type, falls through to 500 "internal error", logged at error level as a failure of pixa's. The error is not an upstream error, so it is not negative-cached: every request for that URL fetches the whole body again.

How it fails: a misconfigured origin serves a 20 MB JPEG as image/png; each request to pixa downloads 20 MB, answers 500, and logs an error, with no five-minute pause, while the operator reads the README and expects 415.

Severity: low

Definition of done:

  1. Both image routes answer 415 for ErrMagicByteMismatch and ErrUnknownFormat, and the README names that case; or the README says plainly that this case is 500.
  2. The failure is treated like an upstream error for the negative cache, or the README says it is re-fetched each time; say which.
  3. Test first; make check green.

Model: fable-5-1

Where: `internal/imgcache/service.go` lines 493-497 (`fetchAndProcess` wraps `magic.ErrMagicByteMismatch` and `magic.ErrUnknownFormat` as "content validation failed"); `internal/handlers/image.go` lines 220-259 (`respondImageError`) and `internal/handlers/imageenc.go` lines 152-172 (`handleImageError`), neither of which maps those errors; `README.md` lines 266-270, on `v1.0.0-rc1`. What is wrong: the README says the image's first bytes must match the `Content-Type` and lists 415 for a wrong `Content-Type` and for first bytes libvips reads as another format. The remaining case, a `Content-Type` of one source format over bytes of another (a JPEG served as `image/png`), or bytes that are no image at all under an image `Content-Type`, falls through to 500 "internal error", logged at error level as a failure of pixa's. The error is not an upstream error, so it is not negative-cached: every request for that URL fetches the whole body again. How it fails: a misconfigured origin serves a 20 MB JPEG as `image/png`; each request to pixa downloads 20 MB, answers 500, and logs an error, with no five-minute pause, while the operator reads the README and expects 415. Severity: low Definition of done: 1. Both image routes answer 415 for `ErrMagicByteMismatch` and `ErrUnknownFormat`, and the README names that case; or the README says plainly that this case is 500. 2. The failure is treated like an upstream error for the negative cache, or the README says it is re-fetched each time; say which. 3. Test first; `make check` green. Model: fable-5-1
clawbot self-assigned this 2026-10-13 08:46:11 +02:00
Author
Collaborator

Plan:

  • Both image routes answer 415 for magic.ErrMagicByteMismatch and magic.ErrUnknownFormat, logged as a refusal, not as pixa's own error.
  • The failure is stored in the negative cache like an upstream error, so the URL is not fetched again for five minutes; a request in that time answers as any negative-cache hit does today. README.md names the case, the 415 and what a repeat answers.

Package: internal/imgcache and internal/handlers. Test first on both routes.

Model: opus-5-5

Plan: - Both image routes answer 415 for `magic.ErrMagicByteMismatch` and `magic.ErrUnknownFormat`, logged as a refusal, not as pixa's own error. - The failure is stored in the negative cache like an upstream error, so the URL is not fetched again for five minutes; a request in that time answers as any negative-cache hit does today. `README.md` names the case, the 415 and what a repeat answers. Package: `internal/imgcache` and `internal/handlers`. Test first on both routes. Model: opus-5-5
Author
Collaborator

Question: may one case of the existing test TestService_Get_ConcurrentMissesShareAFailure (internal/imgcache/concurrent_misses_internal_test.go) change? CLAUDE.md needs your approval to change an existing test.

Its case "source fails the magic byte check, not kept" expects the request after a failed first-bytes check to fetch the source again. The fix in #273 keeps that failure in the negative cache for five minutes, as an upstream error is kept, so that request is refused without a fetch and the case fails.

  • Yes (recommended): the case becomes "source fails the magic byte check, kept in the negative cache", expecting ErrNegativeCached and one fetch. Nothing else in the test changes.
  • No: the failure is not kept in the negative cache; every request for that URL downloads the body again, and README.md says so, as this issue's definition of done allows.

Model: opus-5-5

Question: may one case of the existing test `TestService_Get_ConcurrentMissesShareAFailure` (`internal/imgcache/concurrent_misses_internal_test.go`) change? `CLAUDE.md` needs your approval to change an existing test. Its case "source fails the magic byte check, not kept" expects the request after a failed first-bytes check to fetch the source again. The fix in https://git.eeqj.de/sneak/pixa/pulls/273 keeps that failure in the negative cache for five minutes, as an upstream error is kept, so that request is refused without a fetch and the case fails. - Yes (recommended): the case becomes "source fails the magic byte check, kept in the negative cache", expecting `ErrNegativeCached` and one fetch. Nothing else in the test changes. - No: the failure is not kept in the negative cache; every request for that URL downloads the body again, and `README.md` says so, as this issue's definition of done allows. Model: opus-5-5
clawbot removed their assignment 2026-10-15 10:56:28 +02:00
sneak was assigned by clawbot 2026-10-15 10:56:28 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#253