windmill-labs/windmill · error
string(res.Body)
Error message
string(res.Body)
What it means
GetVariable fetches a Windmill variable's decrypted value. When the HTTP response status is not 2xx, the go client surfaces the raw response body (string(res.Body)) as the error message. The text you see is whatever the Windmill API returned — e.g. a JSON error body describing 404 variable not found or 403 forbidden.
Source
Thrown at go-client/windmill.go:51
Client: client,
Workspace: workspace,
}, nil
}
func newBool(b bool) *bool {
return &b
}
func GetVariable(path string) (string, error) {
client, err := GetClient()
if err != nil {
return "", err
}
res, err := client.Client.GetVariableValueWithResponse(context.Background(), client.Workspace, path, &api.GetVariableValueParams{})
if err != nil {
return "", err
}
if res.StatusCode()/100 != 2 {
return "", errors.New(string(res.Body))
}
return *res.JSON200, nil
}
func GetResource(path string) (interface{}, error) {
client, err := GetClient()
if err != nil {
return nil, err
}
params := api.GetResourceValueInterpolatedParams{}
res, err := client.Client.GetResourceValueInterpolatedWithResponse(context.Background(), client.Workspace, path, ¶ms)
if err != nil {
return nil, err
}
if res.StatusCode()/100 != 2 {
return nil, errors.New(string(res.Body))
}
return *res.JSON200, nilView on GitHub (pinned to e474e8803c)
Solutions
- Read the returned body (it contains the API's JSON error, e.g. 404 'Variable not found') and fix the path accordingly
- Verify the workspace in GetClient() matches where the variable lives
- Check that the API token/worker context has permission to read that variable
- Use the Windmill UI or `wmill variable list` to confirm the exact path
Example fix
// before
v, _ := windmill.GetVariable(context.Background(), "secrets/api_key")
// after
v, err := windmill.GetVariable(context.Background(), "secrets/api_key")
if err != nil {
log.Fatalf("get variable: %v", err) // body reveals 404/403 detail
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate the variable path format before calling
if path == "" || !strings.HasPrefix(path, "/") && !strings.HasPrefix(path, "u/") && !strings.HasPrefix(path, "f/") {
return fmt.Errorf("invalid variable path: %q", path)
} Type guard
func isNotFoundVarErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "not found")
} Try / catch
v, err := windmill.GetVariable(ctx, path)
if err != nil {
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "not found") {
// handle missing variable (create it, use default)
} else if strings.Contains(err.Error(), "403") || strings.Contains(err.Error(), "permission") {
// handle access denied
}
return err
} Prevention
- Always check the error from GetVariable — the body names the exact status/cause
- Confirm the workspace and path in the Windmill UI before coding against them
- Use least-privilege tokens with variable read grants
- Centralize variable paths in constants to avoid typos
When it happens
Trigger: windmill.GetVariable(ctx, path) hitting the API and receiving a non-2xx status: variable does not exist at the given path, the workspace is wrong, or the caller's token lacks read permission on the variable.
Common situations: Typo in the variable path; running locally with a token scoped to a different workspace; variables requiring elevated permissions the token doesn't have; deleted/renamed variables after refactoring.
Related errors
- Dependency generation failed: ${queueResponse.status} ${queu
- Resource ${remotePath} uses '!inline_fileset ${dirPath}', bu
- file path must refer to a file.
- File already exists: + filePath
- File already exists: + filePath
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/612d109e26586d61.
Report an issue: GitHub.