wtfutil/wtf · error
errors.New(hibpErr.Message)
Error message
errors.New(hibpErr.Message)
What it means
hibp fetchForAccount validates the HTTP response with validateHTTPResponse, which returns a structured error (status code + message). When validation fails, the returned hibpErr.Message is converted to a Go error and propagated to Fetch. Typical cases are 401 (invalid API key) and 429 (rate limit) from the Have I Been Pwned API.
Source
Thrown at modules/hibp/client.go:63
return nil, err
}
request.Header.Set("User-Agent", userAgent)
request.Header.Set("hibp-api-key", widget.settings.apiKey)
response, getErr := hibpClient.Do(request)
if getErr != nil {
return nil, err
}
body, readErr := io.ReadAll(response.Body)
if readErr != nil {
return nil, err
}
hibpErr := widget.validateHTTPResponse(response.StatusCode, body)
if hibpErr != nil {
return nil, errors.New(hibpErr.Message)
}
stat, err := widget.parseResponseBody(account, body)
if err != nil {
return nil, err
}
return stat, nil
}
func (widget *Widget) parseResponseBody(account string, body []byte) (*Status, error) {
breaches := []Breach{}
stat := NewStatus(account, breaches)
if len(body) == 0 {
// If the body is empty then there's no breaches
return stat, nil
}View on GitHub (pinned to bb838c1ccb)
Solutions
- Set a valid HIBP API key in the widget config (a paid key is required for the breach API)
- Reduce polling frequency to stay under HIBP rate limits
- Check the propagated hibpErr.Message/status — 401 means key issue, 429 means slow down
- Test manually: curl -H 'hibp-api-key: <key>' https://haveibeenpwned.com/api/v3/breachedaccount/<account>
Example fix
// before hibp: apiKey: "" // empty -> 401 refreshInterval: 30 // seconds -> 429 // after hibp: apiKey: "<paid-api-key>" refreshInterval: 3600
Defensive patterns
Strategy: try-catch
Validate before calling
if hibpKey == "" {
return errors.New("HIBP API key required (paid tier for breach lookup)")
}
if time.Since(lastFetch) < time.Hour {
return errors.New("HIBP rate limit: throttle requests")
} Try / catch
breaches, err := fetchForAccount(account)
if err != nil {
var httpErr *hibpHTTPError
if errors.As(err, &httpErr) && httpErr.StatusCode == 429 {
time.Sleep(backoff) // rate-limited: retry later
return fetchForAccount(account)
}
return err
} Prevention
- Use a paid HIBP API key — the v3 breach API rejects free/absent keys
- Honor Retry-After on 429 and keep refresh intervals ≥ hourly
- Rotate and validate keys on schedule
- Test with curl using the hibp-api-key header before wiring configs
When it happens
Trigger: Missing or invalid HIBP API key ($hibpKey) causing 401; exceeding HIBP's request rate limits (429); malformed account queries; any non-success status detected by validateHTTPResponse.
Common situations: Free tier users without the required paid API key for breach searches; running many account checks rapidly and tripping rate limiting; token rotated/expired in the config; corporate proxy intercepting and returning error statuses.
Related errors
- errors.New(msg.Msg)
- %s
- %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/8dd59b50c55b9dbe.
Report an issue: GitHub.