{"record":{"id":"a1f801647ba2e4de","repo":"windmill-labs/windmill","slug":"get-assets-graph-res-status","errorCode":null,"errorMessage":"GET /assets/graph → ${res.status}","messagePattern":"GET /assets/graph → (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte","lineNumber":2238,"sourceCode":"\t\tif (g.runnables.length === 0 && g.assets.length === 0) {\n\t\t\tsetMode('edit', { replace: true })\n\t\t}\n\t})\n\n\tlet graphRes = resource(\n\t\t[() => $workspaceStore, () => folder],\n\t\tasync ([ws, f], _prev, { signal }) => {\n\t\t\tif (!ws || !f) return undefined\n\t\t\tconst base_url = OpenAPI.BASE ?? ''\n\t\t\tconst params = new URLSearchParams({\n\t\t\t\tfolder: f,\n\t\t\t\tasset_kinds: DATA_KINDS.join(',')\n\t\t\t})\n\t\t\tconst res = await fetch(`${base_url}/w/${ws}/assets/graph?${params}`, {\n\t\t\t\tcredentials: 'include',\n\t\t\t\tsignal\n\t\t\t})\n\t\t\tif (!res.ok) throw new Error(`GET /assets/graph → ${res.status}`)\n\t\t\treturn hideDbtRunnables((await res.json()) as AssetGraphResponse)\n\t\t}\n\t)\n\n\t// Folder whose graph is actually rendered. `graphRes.current` is stale-\n\t// while-revalidate on an in-place folder switch, so keying the canvas's\n\t// one-shot initial fit on the route param would fire the new folder's fit\n\t// on the old graph and leave the fresh one unfitted. `folder` is read\n\t// untracked: the key must move only when a graph lands.\n\tlet viewportFitFolder = $state('')\n\t$effect(() => {\n\t\tif (graphRes.current) untrack(() => (viewportFitFolder = folder))\n\t})\n\n\t// Body / inferred-assets prefetch sweep. Watches `g.runnables`; for any\n\t// non-draft path we haven't fetched yet, fetches `getScriptByPath` and\n\t// `inferAssets`, and stores both in their respective only-add caches.\n\t// All three previously-sticky maps (`inferredWritesByPath`,","sourceCodeStart":2220,"sourceCodeEnd":2256,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/routes/(root)/(logged)/pipeline/[folder]/+page.svelte#L2220-L2256","documentation":"The pipeline graph loader fetches GET /w/{ws}/assets/graph and, on any non-OK HTTP response, throws this error embedding the status code. It is the app's own guard so the failed fetch surfaces instead of a confusing JSON parse error on an error body.","triggerScenarios":"Any request to /assets/graph (with asset_kinds=DATA_KINDS) that returns 4xx/5xx: expired session cookie, missing permissions on the workspace, malformed query params, or backend error while computing the dependency graph.","commonSituations":"Session expired while the pipeline tab was open (401); user lacks access to the workspace/folder (403); backend timeout or DB error computing a large asset graph (500); reverse proxy returning 502.","solutions":["Read the status in the message: 401 → re-login, 403 → request workspace access, 500 → check backend logs for the graph endpoint","Refresh the page / re-authenticate and retry the fetch","Check backend logs around /assets/graph for graph-computation failures","Reduce graph size (filter folders/kinds) if the backend times out on huge graphs"],"exampleFix":"// before\nif (!res.ok) throw new Error(`GET /assets/graph → ${res.status}`)\n// after\nif (!res.ok) {\n  const body = await res.text().catch(() => '')\n  throw new Error(`GET /assets/graph → ${res.status}: ${body.slice(0, 200)}`)\n}","handlingStrategy":"try-catch","validationCode":"const res = await fetch(url, { credentials: 'include', signal })\nif (!res.ok) {\n  if (res.status === 401) await reLogin()\n  if (res.status === 403) throw new Error('Missing workspace access for /assets/graph')\n}","typeGuard":"function isOk(res: Response): res is Response & { ok: true } { return res.ok }","tryCatchPattern":"try {\n  const graph = await loadAssetGraph(ws, signal)\n} catch (e) {\n  const m = /→ (\\d{3})/.exec(e.message)\n  if (m?.[1] === '401') redirectToLogin()\n  else sendUserToast(`Failed to load asset graph${m ? ` (HTTP ${m[1]})` : ''}`, true)\n}","preventionTips":["Keep the session alive on long-lived pipeline tabs (refresh token or re-login prompt on 401)","Check workspace permissions before rendering graph-dependent UI","Log the response body on non-OK to distinguish auth vs server errors","Use AbortSignal properly so canceled polls aren't misread as server failures"],"tags":["http","network","fetch","frontend"],"backgroundTag":"http-request-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}