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

  1. Set a valid HIBP API key in the widget config (a paid key is required for the breach API)
  2. Reduce polling frequency to stay under HIBP rate limits
  3. Check the propagated hibpErr.Message/status — 401 means key issue, 429 means slow down
  4. 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

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


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