{"record":{"id":"e39b42025371f076","repo":"AykutSarac/jsoncrack.com","slug":"failed-to-fetch-json","errorCode":null,"errorMessage":"Failed to fetch JSON!","messagePattern":"Failed to fetch JSON!","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/www/src/features/modals/ImportModal/index.tsx","lineNumber":31,"sourceCode":"  const [file, setFile] = React.useState<File | null>(null);\n\n  const setContents = useFile(state => state.setContents);\n  const setFormat = useFile(state => state.setFormat);\n\n  const handleImportFile = () => {\n    if (url) {\n      setFile(null);\n\n      toast.loading(\"Loading...\", { id: \"toastFetch\" });\n      gaEvent(\"fetch_url\");\n\n      return fetch(url)\n        .then(res => res.json())\n        .then(json => {\n          setContents({ contents: JSON.stringify(json, null, 2) });\n          onClose();\n        })\n        .catch(() => toast.error(\"Failed to fetch JSON!\"))\n        .finally(() => toast.dismiss(\"toastFetch\"));\n    } else if (file) {\n      const lastIndex = file.name.lastIndexOf(\".\");\n      const format = file.name.substring(lastIndex + 1);\n      setFormat(format as FileFormat);\n\n      file.text().then(text => {\n        setContents({ contents: text });\n        setFile(null);\n        setURL(\"\");\n        onClose();\n      });\n\n      gaEvent(\"import_file\", { label: format });\n    }\n  };\n\n  return (","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/AykutSarac/jsoncrack.com/blob/3c9af69e23c635356293b6b28cf4cd0af10d1059/apps/www/src/features/modals/ImportModal/index.tsx#L13-L49","documentation":"Toast shown when fetching a remote URL via the Import modal fails. The promise chain is fetch(url).then(res => res.json()) with a single .catch. It fires for network errors, non-2xx responses, CORS rejections, or a response body that is not valid JSON (res.json() throws SyntaxError). All failure modes collapse into the same generic message.","triggerScenarios":"Entering a URL that is unreachable, returns HTML/text instead of JSON, lacks CORS headers (browser blocks the read), returns 4xx/5xx, or requires auth. The catch at ImportModal/index.tsx:31 swallows the error without logging it.","commonSituations":"Fetching from an API without enabling CORS on the server; pasting a URL to an HTML error page; pointing at a private/local network URL from a deployed site; URL returning JSON wrapped in JSONP or with a BOM.","solutions":["Ensure the remote endpoint sends Access-Control-Allow-Origin (or use a CORS proxy in development).","Check res.ok and res.headers content-type before calling res.json(), and throw a clear error otherwise.","Log the caught error (it is currently swallowed) to diagnose network vs parse failure.","Verify the URL returns strict JSON by opening it directly in the browser first."],"exampleFix":"// before\nreturn fetch(url)\n  .then(res => res.json())\n  .then(json => { setContents({ contents: JSON.stringify(json, null, 2) }); onClose(); })\n  .catch(() => toast.error(\"Failed to fetch JSON!\"))\n\n// after — distinguish HTTP vs parse vs network\nreturn fetch(url)\n  .then(res => {\n    if (!res.ok) throw new Error(`HTTP ${res.status}`);\n    return res.json();\n  })\n  .then(json => { setContents({ contents: JSON.stringify(json, null, 2) }); onClose(); })\n  .catch(err => toast.error(err instanceof SyntaxError ? \"Response is not valid JSON\" : `Failed to fetch JSON: ${err.message}`))","handlingStrategy":"validation","validationCode":"// Pre-check reachability and content-type before parsing the body\nasync function safeFetchJson(url: string): Promise<unknown> {\n  const res = await fetch(url);\n  if (!res.ok) throw new Error(`HTTP ${res.status}`);\n  const type = res.headers.get(\"content-type\") ?? \"\";\n  if (!type.includes(\"json\")) throw new Error(`Expected JSON, got ${type}`);\n  return res.json();\n}","typeGuard":"// Confirm a value is JSON-parseable\nexport function looksLikeJson(text: string): boolean {\n  try { JSON.parse(text); return true; } catch { return false; }\n}","tryCatchPattern":"// Separate network, HTTP, and parse failures\ntry {\n  const json = await safeFetchJson(url);\n  setContents({ contents: JSON.stringify(json, null, 2) });\n} catch (err) {\n  toast.error(`Failed to fetch JSON: ${err.message}`);\n}","preventionTips":["Ensure the endpoint sends CORS headers (Access-Control-Allow-Origin).","Check res.ok and content-type before res.json().","Log the caught error — it is currently swallowed by the empty catch."],"tags":["network","fetch","cors","json","import"],"backgroundTag":null,"analyzedSha":"3c9af69e23c635356293b6b28cf4cd0af10d1059","analyzedAt":"2026-08-12T19:00:27.891Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}