antiwork/gumroad · error · ResponseError
Something went wrong.
Error message
Something went wrong.
What it means
fetchLatestExistingFiles loads previously-uploaded files for re-selection via GET internal_product_existing_product_files_path, racing a 250ms minimum-delay promise so the spinner does not flicker. A non-ok response throws a ResponseError whose message (default 'Something went wrong.') is shown via showAlert. The catch's assertResponseError re-throws anything else — a TypiaError from the body shape assert escapes to the error boundary instead of the alert.
Source
Thrown at app/javascript/components/ProductEdit/ContentTab/index.tsx:582
} | null>(null);
const filteredExistingFiles = React.useMemo(() => {
if (!selectingExistingFiles) return [];
const regex = new RegExp(escapeRegExp(selectingExistingFiles.query), "iu");
return existingFiles.filter((file) => regex.test(file.display_name));
}, [existingFiles, selectingExistingFiles?.query]);
const fetchLatestExistingFiles = async () => {
try {
const [response] = await Promise.all([
request({
method: "GET",
url: Routes.internal_product_existing_product_files_path(uniquePermalink),
accept: "json",
}),
// Enforce minimum loading time to prevent jarring spinner flicker UX on fast connections
new Promise((resolve) => setTimeout(resolve, 250)),
]);
if (!response.ok) throw new ResponseError();
const parsedResponse = typia.assert<{ existing_files: ExistingFileEntry[] }>(await response.json());
setExistingFiles(parsedResponse.existing_files);
} catch (error) {
assertResponseError(error);
showAlert(error.message, "error");
} finally {
setSelectingExistingFiles((state) => (state ? { ...state, isLoading: false } : null));
}
};
const addDropboxFiles = (files: ResponseDropboxFile[]) => {
updateProduct((product) => {
const [updatedFiles, nonModifiedFiles] = partition(product.files, (file) =>
files.some(({ external_id }) => file.id === external_id),
);
product.files = [
...nonModifiedFiles,
...files.map((file) => {View on GitHub (pinned to afeacbd394)
Solutions
- Check the Network tab for the existing_product_files GET: 401 → reload/re-auth; 404 → permalink changed, reload the editor.
- If the alert never fires but the page crashes, the body failed typia — log the raw response once and compare to ExistingFileEntry[].
- Keep the internal route name stable across deploys or version it to tolerate cached bundles.
- Re-open the file picker after reloading to get a consistent permalink and session.
Example fix
// before
} catch (error) {
assertResponseError(error);
showAlert(error.message, 'error');
}
// after — a shape mismatch should degrade to the alert, not escape to the error boundary
} catch (error) {
const message = error instanceof ResponseError ? error.message : 'Could not load your existing files. Reload the page and try again.';
showAlert(message, 'error');
} Defensive patterns
Strategy: try-catch
Validate before calling
const canFetchExistingFiles = (permalink: string | undefined): permalink is string => typeof permalink === 'string' && permalink.length > 0; if (!canFetchExistingFiles(uniquePermalink)) return;
Type guard
const isResponseError = (e: unknown): e is ResponseError => e instanceof ResponseError;
Try / catch
} catch (error) {
const message = error instanceof ResponseError ? error.message : 'Could not load existing files. Reload and try again.';
showAlert(message, 'error'); // TypiaError no longer escapes to the error boundary
} finally {
setSelectingExistingFiles((state) => (state ? { ...state, isLoading: false } : null));
} Prevention
- Convert body-shape failures into a ResponseError before assertResponseError, or they crash the page instead of alerting.
- Re-check session state on window focus for long-lived Content tabs; 401s dominate this endpoint's failures.
- Treat a 404 on this internal route as 'stale bundle or renamed permalink' and prompt a reload.
- Keep the 250ms minimum-delay Promise.all as is — but cancel it if the request already failed so the spinner never lingers.
When it happens
Trigger: GET returning 401 (expired session on a long-open Content tab), 404 (permalink renamed in another tab — URL is built from uniquePermalink), or a 200 whose body is not { existing_files: ExistingFileEntry[] } (TypiaError).
Common situations: Product edited in two tabs with a permalink change in one; internal endpoint renamed in a deploy while cached JS calls the old route; long editing sessions timing out the session; response shape changed by a server deploy ahead of the JS bundle.
Related errors
- ${data.error}
- Could not add this passkey. Please try again.
- Sorry, something went wrong. Please try again.
- ${responseData.error_message}
- Something went wrong.
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/e2b6506886c9dafd.
Report an issue: GitHub.