antiwork/gumroad · error · ResponseError
json.error_message
Error message
json.error_message
What it means
ResponseError thrown at product_dashboard.ts:51 whose message is json.error_message from the POST to Routes.product_duplicates_path(): the duplication kickoff endpoint answered { success: false, error_message } and the client forwards the server's reason. This is the synchronous validation result — the asynchronous part (the actual copy job) is polled separately and fails via error 89.
Source
Thrown at app/javascript/data/product_dashboard.ts:51
});
const json = typia.assert<{ success: true; archived_products_count: number } | { success: false; errors: string[] }>(
await response.json(),
);
if (!json.success) throw new ResponseError(json.errors[0] || "Failed to unarchive product");
return json.archived_products_count;
}
export async function duplicateProduct(permalink: string, productName: string) {
const response = await request({
url: Routes.product_duplicates_path(),
method: "POST",
accept: "json",
data: { id: permalink },
});
const json = typia.assert<{ success: true } | { success: false; error_message: string }>(await response.json());
if (!json.success) throw new ResponseError(json.error_message);
await pollForProductDuplication(permalink, productName);
}
async function pollForProductDuplication(permalink: string, productName: string) {
const response = await request({
url: Routes.product_duplicate_path(permalink),
method: "GET",
accept: "json",
});
const json = typia.assert<{ status: string; error_message?: string }>(await response.json());
if (json.status === "product_duplication_failed") {
const reason = json.error_message
? `Sorry, failed to duplicate '${productName}': ${json.error_message}`
: `Sorry, failed to duplicate '${productName}'. Please try again.`;
throw new ResponseError(reason);
} else if (json.status === "product_duplicated") {View on GitHub (pinned to afeacbd394)
Solutions
- Read the thrown error_message — it is the server's specific refusal reason
- If it reports a duplicate already in progress, wait for the existing job (the poller in error 89 will report it) instead of enqueueing again
- Address the stated constraint (product limit, unsupported type) and retry once resolved
- Disable the duplicate action while a request is in flight to avoid double-enqueue refusals
Defensive patterns
Strategy: try-catch
Type guard
import { assertResponseError } from '$app/utils/request';
assertResponseError(e); Try / catch
try {
await duplicateProduct(permalink, productName);
} catch (e) {
assertResponseError(e);
showError(e.message); // server's refusal (limits, unsupported type, in-progress)
} Prevention
- Show error_message verbatim — it distinguishes limits from transient refusals
- Only offer 'Retry' when the message indicates a transient cause
- Prevent double-enqueue: hide or disable Duplicate while a duplication is pending
When it happens
Trigger: The duplicate endpoint refuses to even enqueue duplication: account/product limits reached, product type or feature not supported for duplication, permalink missing/foreign, or the user lacking permission. The message text is whatever the controller put in error_message.
Common situations: Hitting a per-account product-count cap on a large catalog; duplicating a product type whose files live in external storage still being migrated; double-click on 'Duplicate' enqueueing twice (second call may fail with 'duplication already in progress'); stale dashboard session where the session check fails and the endpoint answers success:false with a generic message.
Related errors
- json.message
- responseData.error_message
- Failed to archive product
- Failed to unarchive product
- Sorry, failed to duplicate '${productName}': ${json.error_me
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/9b75134077813545.
Report an issue: GitHub.