antiwork/gumroad · error · ResponseError
json.message
Error message
json.message
What it means
ResponseError thrown at product_reviews.ts:50 whose message is the server's json.message: the PUT to Routes.product_reviews_set_path() answered { success: false, message } and setProductRating forwards that text. This is the buyer-facing review submit (rating, optional message, optional video options) keyed by permalink + purchaseId + purchaseEmailDigest — the digest proves the reviewer owns the purchase.
Source
Thrown at app/javascript/data/product_reviews.ts:50
purchase_email_digest: purchaseEmailDigest,
rating,
message,
video_options: videoOptions,
},
});
const json = typia.assert<
| {
success: true;
review: {
rating: number;
message: string | null;
video: { id: string; thumbnail_url: string | null } | null;
};
}
| { success: false; message: string }
>(await response.json());
if (!json.success) throw new ResponseError(json.message);
return json.review;
};
export type Review = {
id: string;
rating: number;
message: string | null;
rater: { name: string; avatar_url: string };
purchase_id: string;
created_at: string;
is_new: boolean;
response: {
message: string;
} | null;
video: {
id: string;
thumbnail_url: string | null;View on GitHub (pinned to afeacbd394)
Solutions
- Read the thrown message — it states which guard failed (eligibility, digest, rating, content)
- Validate rating (1–5) and message length client-side before the PUT (see validationCode below)
- Ensure purchaseId/purchaseEmailDigest come from the same purchase link/token currently in context, not one cached from an earlier session
- For video reviews, only submit video_options after the file upload completes and returns a signed id
- Disable the submit control while the PUT is in flight to prevent double-submission refusals
Example fix
// before
// rating sent straight from uncontrolled state
await setProductRating({ permalink, purchaseId, purchaseEmailDigest, rating, message });
// after
if (!Number.isInteger(rating) || rating < 1 || rating > 5) throw new ResponseError('Please choose a star rating.');
await setProductRating({ permalink, purchaseId, purchaseEmailDigest, rating, message }); Defensive patterns
Strategy: validation
Validate before calling
const validReview = (r: { rating: number; message?: string | null }): boolean =>
Number.isInteger(r.rating) && r.rating >= 1 && r.rating <= 5 && (r.message ?? '').length <= 5000; Type guard
import { assertResponseError } from '$app/utils/request';
assertResponseError(e); // e.message is the server's specific refusal (digest, eligibility, rating) Try / catch
try {
await setProductRating({ permalink, purchaseId, purchaseEmailDigest, rating, message, videoOptions });
} catch (e) {
assertResponseError(e);
showError(e.message);
// digest/eligibility messages are not retryable — offer 'view purchase' instead of 'try again'
} Prevention
- Validate rating 1–5 and message length client-side before the PUT
- Take purchaseId and purchaseEmailDigest from the same purchase token in context — never mix sources
- Submit videoOptions only after the upload returns a signed id
- Disable submit while in flight to avoid double-review refusals
When it happens
Trigger: Server refuses the review with success:false: purchase_id/permalink pair not found or not eligible for review (refund, not confirmed), purchase_email_digest mismatch (wrong or forged digest), rating outside 1–5, message failing length/content checks, or video_options referencing a blob that was never uploaded.
Common situations: Review form opened from an old email link where the digest expired or was single-used; rating widget defaulting to 0 when the user skips stars; message pasted at essay length tripping server caps; video flow where thumbnail_signed_id is undefined because the upload widget hadn't finished, sending invalid video_options; submitting the same review twice on a double-click.
Related errors
- responseData.error_message
- json.message
- Failed to archive product
- Failed to unarchive product
- json.error_message
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/dc37c1343baca87d.
Report an issue: GitHub.