wtfutil/wtf · error
%s
Error message
%s
What it means
CircleCI's circleRequest returns resp.Status verbatim (e.g. '404 Not Found') when the API responds with a non-2xx status. Like the Buildkite client, it surfaces the server's status line rather than a parsed API error body, so diagnosing requires mapping the status code to its cause.
Source
Thrown at modules/circleci/client.go:69
url := circleAPIURL.ResolveReference(&url.URL{Path: path, RawQuery: params.Encode()})
req, err := http.NewRequest("GET", url.String(), http.NoBody)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
if err != nil {
return nil, err
}
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
return nil, err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return nil, fmt.Errorf("%s", resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
View on GitHub (pinned to bb838c1ccb)
Solutions
- Check the status code in the message: 401/403 → fix the API token, 404 → fix the project slug (vcs/org/repo)
- Generate a fresh CircleCI personal API token with the needed scopes
- Confirm the project slug format matches CircleCI v2 (e.g. 'gh/myorg/myrepo')
- Retry with backoff for 429/5xx responses
Example fix
// before
client.baseURL = "https://circleci.com/api/v2"
slug := "myrepo" // malformed → 404 Not Found
// after
slug := "gh/myorg/myrepo" // correct v2 project slug
resp, err := client.circleRequest("/project/" + slug + "/builds") Defensive patterns
Strategy: try-catch
Validate before calling
if os.Getenv("CIRCLECI_TOKEN") == "" {
return errors.New("CIRCLECI_TOKEN must be set")
}
if !strings.Contains(projectSlug, "/") {
return fmt.Errorf("project slug %q must be vcs/org/repo", projectSlug)
} Try / catch
builds, err := client.BuildsFor(projectSlug)
if err != nil {
var statusErr error
switch {
case strings.Contains(err.Error(), "401"), strings.Contains(err.Error(), "403"):
statusErr = errors.New("circleci: check API token")
case strings.Contains(err.Error(), "404"):
statusErr = fmt.Errorf("circleci: unknown project %q", projectSlug)
default:
statusErr = err
}
return nil, statusErr
} Prevention
- Use CircleCI v2 slug format (gh/org/repo or bb/org/repo)
- Rotate personal API tokens before expiry
- Retry transient 429/5xx with backoff
When it happens
Trigger: Any CircleCI API v2 call made by circleRequest (invoked from BuildsFor) returning <200 or >299 — invalid CIRCLECI_TOKEN (401), wrong project slug (404), malformed request (400), rate limiting or server errors (429/5xx).
Common situations: Expired CircleCI personal API token; project slug in the wrong 'vcs-slug/org/repo' form; token lacking scope for the project; CircleCI outage or rate limiting.
Related errors
- errors.New(msg.Msg)
- errors.New(hibpErr.Message)
- %s
- unexpected status %d from DEV.to API
- unexpected status code %d from football API
AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03).
Data as JSON: /api/errors/e88718aa5ac00e24.
Report an issue: GitHub.