antiwork/gumroad · error · ResponseError
Sorry, failed to duplicate '${productName}': ${json.error_me
Error message
Sorry, failed to duplicate '${productName}': ${json.error_message} What it means
ResponseError thrown at product_dashboard.ts:68 after pollForProductDuplication GETs Routes.product_duplicate_path(permalink) every 2 seconds and the status comes back 'product_duplication_failed': the asynchronous copy job failed server-side. The message embeds the product name plus json.error_message when present, otherwise the 'Please try again.' fallback. Note the poll loop has no attempt cap — it recurses every 2s indefinitely while status stays 'processing'.
Source
Thrown at app/javascript/data/product_dashboard.ts:68
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") {
return { status: json.status };
}
await new Promise((resolve) => setTimeout(resolve, 2000));
return pollForProductDuplication(permalink, productName);
}
View on GitHub (pinned to afeacbd394)
Solutions
- Read the thrown reason — when error_message is present it names the actual job failure; then check server logs for the duplication worker for the full backtrace
- Retry duplication once (the usual fix for transient file-copy failures), via the same duplicateProduct entry point
- Verify object-storage credentials/bucket policies server-side if the message points at file copying
- Add a max-attempt cap to the 2s poll loop so a wedged 'processing' job surfaces as a timeout error instead of polling forever (see exampleFix)
- If failures cluster for one product, inspect that product's records (orphaned file blobs, oversized content) rather than blaming the job system
Example fix
// before
await new Promise((resolve) => setTimeout(resolve, 2000));
return pollForProductDuplication(permalink, productName);
// after — cap the poll so a wedged job fails loudly
async function pollForProductDuplication(permalink: string, productName: string, attempt = 0) {
// ... existing status checks ...
if (attempt >= 150) throw new ResponseError(`Sorry, duplicating '${productName}' timed out. Please try again.`);
await new Promise((resolve) => setTimeout(resolve, 2000));
return pollForProductDuplication(permalink, productName, attempt + 1);
} Defensive patterns
Strategy: retry
Type guard
import { assertResponseError } from '$app/utils/request';
assertResponseError(e); Try / catch
try {
await pollForProductDuplication(permalink, productName);
} catch (e) {
assertResponseError(e);
const transient = /timed out|try again/i.test(e.message);
if (transient && attempt === 0) return duplicateProduct(permalink, productName); // one retry
showError(e.message); // includes the server's job failure reason when present
} Prevention
- Wrap pollForProductDuplication with an attempt cap so a wedged 'processing' job can't poll forever
- Retry duplication once on transient-sounding messages before surfacing failure
- Log permalink + error_message together — job failures are diagnosed server-side by permalink
When it happens
Trigger: The duplication job enqueued by the product_duplicates endpoint fails and the record's status flips to 'product_duplication_failed': file copy from object storage fails mid-job, a DB constraint trips while cloning records/variants/blobs, the job worker dies after the record was marked in-progress, or the job hits a bug cloning an unusual product shape.
Common situations: Large products (many files/variants) timing out in the copy job; S3 file-copy permission or bucket-policy drift in an environment; job queue retries exhausted after a transient DB issue; browser tab left open polling overnight if the job wedges in 'processing'; error_message arriving empty, leaving users with only the fallback wording.
Related errors
- json.error_message
- json.message
- Failed to archive product
- Failed to unarchive product
- responseData.error_message
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/f57a806e943848a6.
Report an issue: GitHub.