antiwork/gumroad · error · ResponseError
${responseData.error}
Error message
${responseData.error} What it means
createThumbnail (app/javascript/data/thumbnails.ts:9-28) POSTs a signed Active Storage blob id to Routes.link_thumbnails_path and throws ResponseError(responseData.error) when the server answers a parsed body with success:false. This is an application-level rejection: the HTTP exchange completed, but the Rails controller refused to attach the thumbnail and returned its reason in the error string — typically an invalid/expired signed_blob_id, a rejected content type, or a product the seller cannot edit.
Source
Thrown at app/javascript/data/thumbnails.ts:24
export type ThumbnailPayload = { type: "file"; signedBlobId: string };
export const createThumbnail = async (permalink: string, thumbnailPayload: ThumbnailPayload): Promise<Thumbnail> => {
const response = await request({
method: "POST",
accept: "json",
url: Routes.link_thumbnails_path(permalink),
data: {
thumbnail: { signed_blob_id: thumbnailPayload.signedBlobId },
},
});
if (response.ok) {
const responseData = typia.assert<{ success: true; thumbnail: Thumbnail } | { success: false; error: string }>(
await response.json(),
);
if (responseData.success) return responseData.thumbnail;
throw new ResponseError(responseData.error);
}
throw new ResponseError();
};
export const deleteThumbnail = async (permalink: string, thumbnailId: string) => {
const response = await request({
method: "DELETE",
accept: "json",
url: Routes.link_thumbnail_path(permalink, thumbnailId),
});
if (response.ok) {
const responseData = typia.assert<{ success: true; thumbnail: Thumbnail } | { success: false }>(
await response.json(),
);
if (responseData.success) return;
}View on GitHub (pinned to afeacbd394)
Solutions
- Retry the full upload flow — re-run the direct upload so signedBlobId is freshly minted, then POST again
- Verify the direct upload succeeded before calling createThumbnail (check the upload step's own result, not just form state)
- Confirm the file is an accepted image type and under the size limit the controller enforces
- Log/inspect responseData.error — the server states the exact refusal (invalid blob, wrong type, not permitted)
- Ensure the acting seller owns the product identified by permalink
Example fix
// components/ProductEdit/ProductTab/ThumbnailEditor.tsx — only attach a blob that finished uploading
const upload = await directUpload(file); // throws on its own failure
if (!upload.signedBlobId) throw new Error("Upload did not complete");
const thumbnail = await createThumbnail(permalink, { type: "file", signedBlobId: upload.signedBlobId }); Defensive patterns
Strategy: validation
Validate before calling
const canAttach = (p: ThumbnailPayload) =>
typeof p.signedBlobId === "string" && p.signedBlobId.length > 0; // never POST an upload that didn't finish
if (!canAttach(thumbnailPayload)) throw new Error("Upload did not complete"); Type guard
import typia from "typia";
const isThumbnailResponse = typia.is<{ success: true; thumbnail: Thumbnail } | { success: false; error: string }>; Try / catch
try {
return await createThumbnail(permalink, payload);
} catch (e) {
assertResponseError(e);
showError(e.message); // server's refusal: invalid signed_blob_id, bad type, no permission
} Prevention
- Verify the direct upload succeeded before attaching its signed_blob_id
- Re-run the full upload (new blob, new signed id) on retry — never reuse the old signed id
- Confirm the image type/size before upload to avoid server-side rejection
When it happens
Trigger: Uploading a product thumbnail in ProductEdit/ProductTab/ThumbnailEditor.tsx:62 when the direct-upload blob never actually uploaded (signedBlobId references nothing); the signed id expired before the POST; the file type/size is rejected server-side; the permalink belongs to a product not owned by the acting seller.
Common situations: Direct upload to Active Storage silently failing (network drop between S3 upload and attach step); reusing a signed_blob_id captured in an old form state after the upload was redone; tests posting fixture signed ids that were never generated; product permissions changed while the edit page was open.
Related errors
- Something went wrong.
- Something went wrong.
- ${responseData.error}
- ${data.error}
- Attach at least one file before completing this commission.
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/48d8ece6a2f7c87c.
Report an issue: GitHub.