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

  1. Check the status code in the message: 401/403 → fix the API token, 404 → fix the project slug (vcs/org/repo)
  2. Generate a fresh CircleCI personal API token with the needed scopes
  3. Confirm the project slug format matches CircleCI v2 (e.g. 'gh/myorg/myrepo')
  4. 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

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


AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03). Data as JSON: /api/errors/e88718aa5ac00e24. Report an issue: GitHub.