{"record":{"id":"4e00053a9da55abd","repo":"AykutSarac/jsoncrack.com","slug":"failed-to-fetch-document-from-url","errorCode":null,"errorMessage":"Failed to fetch document from URL!","messagePattern":"Failed to fetch document from URL!","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/www/src/store/useFile.ts","lineNumber":139,"sourceCode":"    } catch (error: any) {\n      if (error?.mark?.snippet) return set({ error: error.mark.snippet });\n      if (error?.message) set({ error: error.message });\n      useJson.setState({ loading: false });\n    }\n  },\n  setError: error => set({ error }),\n  setHasChanges: hasChanges => set({ hasChanges }),\n  fetchUrl: async url => {\n    try {\n      const res = await fetch(url);\n      const json = await res.json();\n      const jsonStr = JSON.stringify(json, null, 2);\n\n      get().setContents({ contents: jsonStr });\n      return useJson.setState({ json: jsonStr, loading: false });\n    } catch {\n      get().clear();\n      toast.error(\"Failed to fetch document from URL!\");\n    }\n  },\n  checkEditorSession: (url, widget) => {\n    if (url && typeof url === \"string\" && isURL(url)) {\n      return get().fetchUrl(url);\n    }\n\n    let contents = defaultJson;\n    const sessionContent = sessionStorage.getItem(\"content\") as string | null;\n    const format = sessionStorage.getItem(\"format\") as FileFormat | null;\n    if (sessionContent && !widget) contents = sessionContent;\n\n    if (format) set({ format });\n    get().setContents({ contents, hasChanges: false });\n  },\n}));\n\nexport default useFile;","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/AykutSarac/jsoncrack.com/blob/3c9af69e23c635356293b6b28cf4cd0af10d1059/apps/www/src/store/useFile.ts#L121-L157","documentation":"Toast from useFile.fetchUrl when the fetch or response parse fails. The action does fetch(url) then res.json(); the catch clears ALL editor content (get().clear()) and shows this toast. Note it does not check res.ok, so a 4xx/5xx response that returns HTML will also throw at res.json() and trigger the destructive clear.","triggerScenarios":"URL unreachable; CORS rejection; response is not JSON (e.g. an HTML error page); 4xx/5xx; network offline. Because get().clear() runs in the catch, the editor content is wiped on any failure — a notable side effect.","commonSituations":"Loading a URL that requires auth; pointing at an endpoint returning JSON-wrapped-in-HTML errors; cross-origin without CORS; offline/spotty network during fetch.","solutions":["Check res.ok and the content-type before calling res.json() to avoid treating HTML errors as JSON failures.","Do not call get().clear() on fetch failure — keep existing content so users do not lose their work.","Log the caught error to distinguish network from parse failure.","Ensure the endpoint sends CORS headers and returns strict JSON."],"exampleFix":"// before\nfetchUrl: async url => {\n  try {\n    const res = await fetch(url);\n    const json = await res.json();\n    const jsonStr = JSON.stringify(json, null, 2);\n    get().setContents({ contents: jsonStr });\n    return useJson.setState({ json: jsonStr, loading: false });\n  } catch {\n    get().clear();\n    toast.error(\"Failed to fetch document from URL!\");\n  }\n},\n\n// after — preserve content, validate response\nfetchUrl: async url => {\n  try {\n    const res = await fetch(url);\n    if (!res.ok) throw new Error(`HTTP ${res.status}`);\n    const json = await res.json();\n    const jsonStr = JSON.stringify(json, null, 2);\n    get().setContents({ contents: jsonStr });\n    return useJson.setState({ json: jsonStr, loading: false });\n  } catch (err) {\n    toast.error(`Failed to fetch document from URL: ${err.message}`);\n  }\n},","handlingStrategy":"validation","validationCode":"// Validate URL + response before ingestion; avoid destructive clear\nexport async function fetchJsonSafe(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(`Not JSON (${type})`);\n  return res.json();\n}","typeGuard":"// Confirm a URL string is well-formed http(s)\nexport function isHttpUrl(value: string): boolean {\n  try { const u = new URL(value); return u.protocol === \"http:\" || u.protocol === \"https:\"; }\n  catch { return false; }\n}","tryCatchPattern":"// Preserve content; report the real HTTP/parse cause\ntry {\n  const json = await fetchJsonSafe(url);\n  get().setContents({ contents: JSON.stringify(json, null, 2) });\n} catch (err) {\n  toast.error(`Failed to fetch document from URL: ${err.message}`);\n}","preventionTips":["Check res.ok and content-type before res.json().","Do not clear editor content on fetch failure (users lose their work).","Confirm the endpoint sends CORS headers and returns strict JSON."],"tags":["network","fetch","cors","json","zustand","destructive"],"backgroundTag":null,"analyzedSha":"3c9af69e23c635356293b6b28cf4cd0af10d1059","analyzedAt":"2026-08-12T19:00:27.891Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}