quak helper fix-missing-thumbnails never uploads: the PUT lacks the signed Content-MD5 header #238

Closed
opened 2026-11-11 21:22:23 +01:00 by clawbot · 1 comment
Collaborator

quak helper fix-missing-thumbnails cannot upload any thumbnail: the upload is refused every time, so no file is ever fixed.

Steps

Found against a local self-hosted Ente server (ghcr.io/ente/server, MinIO-compatible storage), logged in with quak login:

  1. Own an album holding a JPEG whose thumbnail object is gone from storage. quak helper list-missing-thumbnails lists it with thumbnail not found (HTTP 404).
  2. Run quak helper fix-missing-thumbnails (or --file with that file's ID).

What happened

The helper downloads the original and makes the thumbnail, then fails at the upload:

[Holiday] Uploading thumbnail (29907 bytes)...
[Holiday] FAILED img_0001.jpg: PUT to presigned URL failed: HTTP 400

Exit status 1; list-missing-thumbnails still lists the file. The storage's answer is AccessDenied: There were headers present in the request which were not signed.

Cause: ApiClient.getUploadURL in src/api/client.ts sends contentMD5 to POST /files/upload-url, so the server signs the MD5 into the URL (X-Amz-SignedHeaders=content-length;content-md5;host). ApiClient.putFile then sends the PUT with only Content-Type and Content-Length. The same PUT with a Content-MD5 header carrying the value sent to /files/upload-url returns 200.

What should happen

  • The PUT carries Content-MD5 with the base64 MD5 that was sent to /files/upload-url.
  • fix-missing-thumbnails reports the file as fixed, and a following list-missing-thumbnails no longer lists it.
  • A test fails when the PUT lacks the header: the fake server in test/ente-server.ts refuses such a PUT, as the real storage does.

Not checked: Ente's hosted service. It runs the same server code, so the same signed header is expected there.

Model: opus-5-5

`quak helper fix-missing-thumbnails` cannot upload any thumbnail: the upload is refused every time, so no file is ever fixed. ## Steps Found against a local self-hosted Ente server (`ghcr.io/ente/server`, MinIO-compatible storage), logged in with `quak login`: 1. Own an album holding a JPEG whose thumbnail object is gone from storage. `quak helper list-missing-thumbnails` lists it with `thumbnail not found (HTTP 404)`. 2. Run `quak helper fix-missing-thumbnails` (or `--file` with that file's ID). ## What happened The helper downloads the original and makes the thumbnail, then fails at the upload: ``` [Holiday] Uploading thumbnail (29907 bytes)... [Holiday] FAILED img_0001.jpg: PUT to presigned URL failed: HTTP 400 ``` Exit status 1; `list-missing-thumbnails` still lists the file. The storage's answer is `AccessDenied: There were headers present in the request which were not signed`. Cause: `ApiClient.getUploadURL` in `src/api/client.ts` sends `contentMD5` to `POST /files/upload-url`, so the server signs the MD5 into the URL (`X-Amz-SignedHeaders=content-length;content-md5;host`). `ApiClient.putFile` then sends the PUT with only `Content-Type` and `Content-Length`. The same PUT with a `Content-MD5` header carrying the value sent to `/files/upload-url` returns 200. ## What should happen - The PUT carries `Content-MD5` with the base64 MD5 that was sent to `/files/upload-url`. - `fix-missing-thumbnails` reports the file as `fixed`, and a following `list-missing-thumbnails` no longer lists it. - A test fails when the PUT lacks the header: the fake server in `test/ente-server.ts` refuses such a PUT, as the real storage does. Not checked: Ente's hosted service. It runs the same server code, so the same signed header is expected there. Model: opus-5-5
clawbot self-assigned this 2026-11-11 21:22:23 +01:00
Author
Collaborator

Fixed in #249 (branch issue-238-put-content-md5): putFile sends the MD5 given to /files/upload-url as Content-MD5, and the thumbnail test's fake storage refuses a PUT without it.

Deviation: the refusing fake is in test/thumbnails/thumbnails.test.ts, not test/ente-server.ts, which serves no uploads.

Model: opus-5-5

Fixed in https://git.eeqj.de/sneak/quak/pulls/249 (branch `issue-238-put-content-md5`): `putFile` sends the MD5 given to `/files/upload-url` as `Content-MD5`, and the thumbnail test's fake storage refuses a PUT without it. Deviation: the refusing fake is in `test/thumbnails/thumbnails.test.ts`, not `test/ente-server.ts`, which serves no uploads. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/quak#238