{"record":{"id":"3d22eb8fa0cac488","repo":"windmill-labs/windmill","slug":"job-jobid-was-not-successful-json-stringify","errorCode":null,"errorMessage":"Job ${jobId} was not successful: ${JSON.stringify(error)}","messagePattern":"Job (.+?) was not successful: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"backend/windmill-runtime-nativets/src/windmill-client.js","lineNumber":9919,"sourceCode":"  const jobId = await runScriptAsync(path, hash_, args);\n  return await waitJob(jobId, verbose);\n}\nasync function waitJob(jobId, verbose = false) {\n  while (true) {\n    const resultRes = await getResultMaybe(jobId);\n    const started = resultRes.started;\n    const completed = resultRes.completed;\n    const success = resultRes.success;\n    if (!started && verbose) {\n      console.info(`job ${jobId} has not started yet`);\n    }\n    if (completed) {\n      const result = resultRes.result;\n      if (success) {\n        return result;\n      } else {\n        const error = result.error;\n        throw new Error(\n          `Job ${jobId} was not successful: ${JSON.stringify(error)}`\n        );\n      }\n    }\n    if (verbose) {\n      console.info(`sleeping 0.5 seconds for jobId: ${jobId}`);\n    }\n    await new Promise((resolve2) => setTimeout(resolve2, 500));\n  }\n}\nasync function getResultMaybe(jobId) {\n  !clientSet && setClient();\n  const workspace = getWorkspace();\n  return await JobService.getCompletedJobResultMaybe({ workspace, id: jobId });\n}\nvar STRIP_COMMENTS =\n  /(\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/)|(\\s*=[^,\\)]*(('(?:\\\\'|[^'\\r\\n])*')|(\"(?:\\\\\"|[^\"\\r\\n])*\"))|(\\s*=[^,\\)]*))/gm;\nvar ARGUMENT_NAMES = /([^\\s,]+)/g;","sourceCodeStart":9901,"sourceCodeEnd":9937,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-runtime-nativets/src/windmill-client.js#L9901-L9937","documentation":"When waiting on a Windmill job by id, the poller sees the job completed but its result carries an error field instead of a successful result. The client throws an Error embedding the jobId and a JSON dump of the error object so the script's own failure is visible to the caller of runScript/waitJob.","triggerScenarios":"Calling runScript/runScriptAsync + waiting for the resulting job when the executed script throws, is denied (job error: permissions, rate limit), or fails at runtime; result.error is populated on completion and this branch fires instead of returning the result.","commonSituations":"The child script itself raised an exception, input args didn't match the script signature, the script exceeded its timeout or memory limit, or the worker crashed the job.","solutions":["Inspect the JSON error payload in the message — it names the root cause (script exception, worker crash, denied, timeout).","Open the job's run page in the Windmill UI / GET /jobs/u/get/{jobId} for the full logs and stack trace.","Fix the underlying script bug or pass correct args; re-run.","If the error is transient (worker OOM, timeout), increase limits or retry with backoff."],"exampleFix":"// before\nconst result = await windmill.runScript(path, hash_, args); // throws on job error\n// after\ntry {\n  const result = await windmill.runScript(path, hash_, args);\n} catch (e) {\n  const detail = /Job \\S+ was not successful: (.*)/.exec(e.message);\n  if (detail) console.error('Job failed:', JSON.parse(detail[1]));\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Validate args against the script's signature before running\nconst sig = await client.getScriptArgsByPath({ workspace, path });\nfor (const req of sig.args.filter(a => a.has_default === false)) {\n  if (!(req.name in args)) throw new Error(`Missing arg ${req.name} for ${path}`);\n}","typeGuard":"function isJobFailure(e) { return /Job \\S+ was not successful:/.test(e?.message ?? ''); }\nfunction parseJobError(e) { const m = /Job \\S+ was not successful: (.*)$/.exec(e.message); return m ? JSON.parse(m[1]) : null; }","tryCatchPattern":"try {\n  const result = await windmill.runScript(path, hash_, args);\n} catch (e) {\n  if (isJobFailure(e)) {\n    const jobError = parseJobError(e);\n    console.error('Underlying job error:', jobError);\n    // fetch full logs via GET /jobs/u/get/logs/{jobId}\n  }\n  throw e;\n}","preventionTips":["Test the script standalone in the Windmill UI before invoking it from code.","Match arg names/types to the script signature; use the signature endpoint.","Watch timeouts/memory limits for heavy jobs and set explicit timeouts."],"tags":["jobs","script-execution","runtime-error","polling"],"backgroundTag":"job-execution-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"}