Billionmail/BillionMail · error

API key validation failed: %w

Error message

API key validation failed: %w

What it means

Testing validates the API key by issuing a GET to the /models endpoint via testAPIKeyValidity. Any failure there (non-200/401/404 status, network error, bad request) is wrapped as 'API key validation failed: %w'. The wrapped cause reveals whether it was auth-related or another HTTP problem.

Source

Thrown at core/internal/service/askai/supplier.go:501

	if supplierName == "" || baseUrl == "" || apiKey == "" {
		return errors.New("supplier name, base URL, and API key are required")
	}

	// Validate base URL format
	parsedUrl, err := url.ParseRequestURI(baseUrl)
	if err != nil {
		return fmt.Errorf("invalid base URL format: %w", err)
	}
	if parsedUrl.Scheme != "http" && parsedUrl.Scheme != "https" {
		return errors.New("base URL must use http or https protocol")
	}
	// Ensure the base URL ends with a slash
	if err := testBaseURLAccessibility(baseUrl); err != nil {
		return fmt.Errorf("base URL accessibility test failed: %w", err)
	}
	// Validate API key by making a request to the models endpoint
	if err := testAPIKeyValidity(baseUrl, apiKey); err != nil {
		return fmt.Errorf("API key validation failed: %w", err)
	}

	return nil
}

// testBaseURLAccessibility checks if the base URL is accessible by sending a HEAD request.
// It returns an error if the request fails or if the response status is not OK (200).
func testBaseURLAccessibility(baseUrl string) error {
	client := &http.Client{Timeout: 3 * time.Second}
	resp, err := client.Head(baseUrl)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

// testAPIKeyValidity checks if the provided API key is valid by making a GET request to the models endpoint.

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect the wrapped inner error/status to see the actual response code
  2. Re-copy the API key from the provider dashboard and confirm it matches the chosen baseUrl's provider
  3. Check the account/key status on the provider side (revoked, expired, no credit)
  4. Test the key manually: curl -H 'Authorization: Bearer <key>' <baseUrl>/models
  5. Verify the endpoint path exists for the provider version in use

Example fix

// before
err := askai.Testing(name, url, "sk-...truncated") // key malformed
// after
apiKey := strings.TrimSpace(os.Getenv("PROVIDER_API_KEY"))
if apiKey == "" || len(apiKey) < 20 { return errors.New("API key looks invalid") }
err := askai.Testing(name, url, apiKey)
Defensive patterns

Strategy: try-catch

Validate before calling

func keyLooksPlausible(key string) bool {
    k := strings.TrimSpace(key)
    return len(k) >= 20 && !strings.ContainsAny(k, " \n\t")
}
if !keyLooksPlausible(apiKey) { return errors.New("API key missing or malformed") }

Try / catch

if err := askai.Testing(name, baseUrl, apiKey); err != nil {
    var detail string
    if strings.HasPrefix(err.Error(), "API key validation failed:") {
        detail = strings.TrimPrefix(err.Error(), "API key validation failed: ")
        return fmt.Errorf("check your key at the provider dashboard: %s", detail)
    }
    return err
}

Prevention

When it happens

Trigger: Calling askai.Testing with an invalid, revoked, or malformed API key; the models endpoint returning an unexpected status (403, 500); network failure during the GET request.

Common situations: Copied key missing characters or containing whitespace; key revoked or rotated on the provider side; key valid for a different provider/endpoint than baseUrl points to; provider outage returning 5xx; account lacks access to the models endpoint (403).

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/790a2b0f9970d291. Report an issue: GitHub.