{"record":{"id":"e2b6506886c9dafd","repo":"antiwork/gumroad","slug":"something-went-wrong-e2b650","errorCode":null,"errorMessage":"Something went wrong.","messagePattern":"Something went wrong\\.","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/components/ProductEdit/ContentTab/index.tsx","lineNumber":582,"sourceCode":"  } | null>(null);\n  const filteredExistingFiles = React.useMemo(() => {\n    if (!selectingExistingFiles) return [];\n    const regex = new RegExp(escapeRegExp(selectingExistingFiles.query), \"iu\");\n    return existingFiles.filter((file) => regex.test(file.display_name));\n  }, [existingFiles, selectingExistingFiles?.query]);\n\n  const fetchLatestExistingFiles = async () => {\n    try {\n      const [response] = await Promise.all([\n        request({\n          method: \"GET\",\n          url: Routes.internal_product_existing_product_files_path(uniquePermalink),\n          accept: \"json\",\n        }),\n        // Enforce minimum loading time to prevent jarring spinner flicker UX on fast connections\n        new Promise((resolve) => setTimeout(resolve, 250)),\n      ]);\n      if (!response.ok) throw new ResponseError();\n      const parsedResponse = typia.assert<{ existing_files: ExistingFileEntry[] }>(await response.json());\n      setExistingFiles(parsedResponse.existing_files);\n    } catch (error) {\n      assertResponseError(error);\n      showAlert(error.message, \"error\");\n    } finally {\n      setSelectingExistingFiles((state) => (state ? { ...state, isLoading: false } : null));\n    }\n  };\n\n  const addDropboxFiles = (files: ResponseDropboxFile[]) => {\n    updateProduct((product) => {\n      const [updatedFiles, nonModifiedFiles] = partition(product.files, (file) =>\n        files.some(({ external_id }) => file.id === external_id),\n      );\n      product.files = [\n        ...nonModifiedFiles,\n        ...files.map((file) => {","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/components/ProductEdit/ContentTab/index.tsx#L564-L600","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n} catch (error) {\n  assertResponseError(error);\n  showAlert(error.message, 'error');\n}\n\n// after — a shape mismatch should degrade to the alert, not escape to the error boundary\n} catch (error) {\n  const message = error instanceof ResponseError ? error.message : 'Could not load your existing files. Reload the page and try again.';\n  showAlert(message, 'error');\n}","handlingStrategy":"try-catch","validationCode":"const canFetchExistingFiles = (permalink: string | undefined): permalink is string =>\n  typeof permalink === 'string' && permalink.length > 0;\n\nif (!canFetchExistingFiles(uniquePermalink)) return;","typeGuard":"const isResponseError = (e: unknown): e is ResponseError => e instanceof ResponseError;","tryCatchPattern":"} catch (error) {\n  const message = error instanceof ResponseError ? error.message : 'Could not load existing files. Reload and try again.';\n  showAlert(message, 'error'); // TypiaError no longer escapes to the error boundary\n} finally {\n  setSelectingExistingFiles((state) => (state ? { ...state, isLoading: false } : null));\n}","preventionTips":["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."],"tags":["http","product-files","typia","response-not-ok"],"backgroundTag":"http-request-failed","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}