windmill-labs/windmill · error · ApiError

ApiError with mapped HTTP status message (e.g. "Not Found",

Error message

ApiError with mapped HTTP status message (e.g. "Not Found", "Internal Server Error") for non-2xx responses

What it means

This generated OpenAPI client (windmill-client.js) maps known HTTP status codes to their reason phrases ("Not Found", "Internal Server Error", etc., extendable via options.errors) and throws an ApiError carrying the full response whenever the server returns a non-2xx status with a mapped message. It is the client's way of surfacing that the Windmill API rejected the request at the HTTP level.

Source

Thrown at backend/windmill-runtime-nativets/src/windmill-client.js:3598

    429: "Too Many Requests",
    431: "Request Header Fields Too Large",
    451: "Unavailable For Legal Reasons",
    500: "Internal Server Error",
    501: "Not Implemented",
    502: "Bad Gateway",
    503: "Service Unavailable",
    504: "Gateway Timeout",
    505: "HTTP Version Not Supported",
    506: "Variant Also Negotiates",
    507: "Insufficient Storage",
    508: "Loop Detected",
    510: "Not Extended",
    511: "Network Authentication Required",
    ...options.errors,
  };
  const error = errors[result.status];
  if (error) {
    throw new ApiError(options, result, error);
  }
  if (!result.ok) {
    const errorStatus = result.status ?? "unknown";
    const errorStatusText = result.statusText ?? "unknown";
    const errorBody = (() => {
      try {
        return JSON.stringify(result.body, null, 2);
      } catch (e) {
        return void 0;
      }
    })();
    throw new ApiError(
      options,
      result,
      `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`
    );
  }
};

View on GitHub (pinned to e474e8803c)

Solutions

  1. Read error.response.status and .body to identify the actual cause (auth vs not-found vs server error).
  2. For 401/403, refresh the Windmill token (WM_TOKEN) and check the token's workspace/permissions.
  3. For 404, verify the script/job path or id and that the baseUrl points at the correct instance.
  4. For 5xx/429, retry with backoff; check the Windmill server logs for the underlying failure.

Example fix

// before
const job = await client.getJob({ workspace, id });
// after
try {
  const job = await client.getJob({ workspace, id });
} catch (e) {
  if (e instanceof ApiError && e.status === 404) {
    console.error(`Job ${id} not found in workspace ${workspace}`);
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!token) throw new Error('WM_TOKEN missing before calling Windmill API');
if (!workspace) throw new Error('workspace id missing');

Type guard

function isApiError(e) { return e instanceof ApiError && typeof e.status === 'number'; }

Try / catch

try {
  const res = await client.getJob({ workspace, id });
} catch (e) {
  if (isApiError(e)) {
    switch (e.status) {
      case 401: case 403: return refreshTokenAndRetry();
      case 404: return handleNotFound(id);
      default: if (e.status >= 500 || e.status === 429) return retryWithBackoff();
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: Any windmill-client SDK call (e.g. getJob, runScript, listWorkspaces) whose fetch receives a non-2xx response with a status in the errors map: 404 for a missing script/job/workspace, 401/403 for bad token or permissions, 409 conflicts, 429 rate limits, 5xx server errors.

Common situations: Wrong workspace id in the path, an expired or revoked Windmill token, referencing a script path that doesn't exist, requesting a job that was purged, or the server returning 500 during an internal failure.

Understand the failure class

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/950b2ee696e882d3. Report an issue: GitHub.