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

  1. Check the Network tab for the existing_product_files GET: 401 → reload/re-auth; 404 → permalink changed, reload the editor.
  2. If the alert never fires but the page crashes, the body failed typia — log the raw response once and compare to ExistingFileEntry[].
  3. Keep the internal route name stable across deploys or version it to tolerate cached bundles.
  4. 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

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


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/e2b6506886c9dafd. Report an issue: GitHub.