{"record":{"id":"0a1e636a06ecbecc","repo":"windmill-labs/windmill","slug":"an-error-occurred","errorCode":null,"errorMessage":"An error occurred","messagePattern":"An error occurred","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/script_helpers.ts","lineNumber":556,"sourceCode":"\t}\n\n\tconst requestOptions: RequestInit = {\n\t\tmethod: method || 'GET',\n\t\theaders: headers || {}\n\t}\n\n\tif (requestOptions.method !== 'GET' && requestOptions.method !== 'HEAD' && body !== undefined) {\n\t\trequestOptions.body = JSON.stringify(body)\n\t\trequestOptions.headers = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\t...requestOptions.headers\n\t\t}\n\t}\n\n\treturn await fetch(url, requestOptions)\n\t\t.then((res) => res.json())\n\t\t.catch(() => {\n\t\t\tthrow new Error('An error occurred')\n\t\t})\n}`\n\nconst BASH_INIT_CODE = `# shellcheck shell=bash\n# arguments of the form X=\"$I\" are parsed as parameters X of type string\nmsg=\"$1\"\ndflt=\"\\${2:-default value}\"\n\n# the last line of the stdout is the return value\n# unless you write json to './result.json' or a string to './result.out'\necho \"Hello $msg\"\n`\n\nconst DENO_INIT_CODE_TRIGGER = `import * as wmill from \"npm:windmill-client@${__pkg__.version}\"\n\nexport async function main() {\n\n  // A common trigger script would follow this pattern:","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/script_helpers.ts#L538-L574","documentation":"The generated 'fetch' starter script for Windmill replaces any failure from fetch() or res.json() with a generic Error('An error occurred'). The real cause (network failure, DNS error, HTTP 4xx/5xx status, or a non-JSON response body that breaks JSON parsing) is swallowed by the catch with no argument, so the developer only sees the opaque message.","triggerScenarios":"Running the FETCH_INIT_CODE starter script when: the url is unreachable or blocked (network/CORS), the server returns a non-2xx status (fetch does not throw on HTTP errors), or the response body is not valid JSON so res.json() rejects.","commonSituations":"Typing a wrong or internal-only URL; calling an API that returns HTML error pages or empty bodies; missing auth headers so the server returns 401 with a non-JSON body; TypeScript/Deno environments where fetch fails on TLS or DNS.","solutions":["Log the actual error and response status instead of discarding it: catch((err) => { console.error(err); throw err })","Check res.ok / res.status before calling res.json() and surface the body text on failure","Verify the target URL is reachable from the worker (curl it from the same environment)","If the response may not be JSON, use res.text() and parse conditionally"],"exampleFix":"// before\nreturn await fetch(url, requestOptions)\n  .then((res) => res.json())\n  .catch(() => {\n    throw new Error('An error occurred')\n  })\n// after\nconst res = await fetch(url, requestOptions)\nif (!res.ok) {\n  throw new Error(`HTTP ${res.status}: ${await res.text()}`)\n}\nreturn await res.json()","handlingStrategy":"try-catch","validationCode":"// before calling the script/fetch\nif (!url || !/^https?:\\/\\//.test(url)) {\n  throw new Error(`Invalid URL: ${url}`)\n}","typeGuard":"function isErrorResponse(res: Response): boolean {\n  return !res.ok\n}","tryCatchPattern":"try {\n  const res = await fetch(url, requestOptions)\n  if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`)\n  return await res.json()\n} catch (err) {\n  // preserve the original cause instead of masking it\n  throw new Error(`Fetch to ${url} failed: ${err instanceof Error ? err.message : err}`)\n}","preventionTips":["Never use a bare catch that discards the original error","Always check res.ok before res.json()","Confirm the URL is reachable from the worker environment, not just locally","Log response status and body text on failure"],"tags":["network","fetch","json","error-masking"],"backgroundTag":"fetch-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"}