ory/kratos · warning · wrapped sentinel error

ErrNetworkFailure

ErrNetworkFailure

Error message

ErrNetworkFailure wrapped: %s (network failure during HIBP range request)

What it means

The password validator checks leaked passwords via the HaveIBeenPwned range API. fetch performs the HTTP GET with a resilient HTTP client; if the request itself fails (connection error, timeout, DNS failure), the error is wrapped in ErrNetworkFailure with the underlying cause. This keeps the failure classifiable and subject to ignore_network_errors.

Solutions

  1. Set ignore_network_errors: true in the password HIBP config so registration proceeds when HIBP is unreachable.
  2. Verify outbound connectivity: curl https://api.pwnedpasswords.com/range/AAAAA from the server.
  3. Check proxy/firewall rules and allow egress to api.pwnedpasswords.com (HTTPS/443).
  4. Inspect the wrapped cause for the exact transport error (timeout vs refused vs DNS).
Defensive patterns

Strategy: fallback

Validate before calling

conn, err := net.DialTimeout("tcp", "api.pwnedpasswords.com:443", 2*time.Second)
if err != nil { /* egress to HIBP is blocked; enable ignore_network_errors */ }

Try / catch

if errors.Is(err, strategy.ErrNetworkFailure) {
  if cfg.IgnoreNetworkErrors { return allowed /* skip HIBP check */ }
  return err
}

Prevention

When it happens

Trigger: Calling fetch (via validate) when retryablehttp request execution fails: api.pwnedpasswords.com unreachable, network outage, connection timeout (1s connection timeout), or proxy misconfiguration.

Common situations: Egress firewall blocking api.pwnedpasswords.com, DNS failures in restricted clusters, HIBP outages/rate limiting at connection level, or missing outbound internet access in air-gapped deployments.

Related errors


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/acb101980e2c35e4. Report an issue: GitHub.

Appendix: source

Thrown at selfservice/strategy/password/validator.go:134

					greatestLength = curr
				}
				lengths[i*len(b)+j] = curr
			}
		}
	}
	return greatestLength
}

func (s *DefaultPasswordValidator) fetch(ctx context.Context, hpw []byte, apiDNSName string) (int64, error) {
	prefix := fmt.Sprintf("%X", hpw)[0:5]
	loc := fmt.Sprintf("https://%s/range/%s", apiDNSName, prefix)
	req, err := retryablehttp.NewRequestWithContext(ctx, "GET", loc, nil)
	if err != nil {
		return 0, err
	}
	res, err := s.reg.HTTPClient(ctx, httpx.ResilientClientWithConnectionTimeout(time.Second)).Do(req)
	if err != nil {
		return 0, errors.Wrapf(ErrNetworkFailure, "%s", err)
	}
	defer func() { _ = res.Body.Close() }()

	if res.StatusCode != http.StatusOK {
		return 0, errors.Wrapf(ErrUnexpectedStatusCode, "%d", res.StatusCode)
	}

	var thisCount int64

	sc := bufio.NewScanner(res.Body)
	for sc.Scan() {
		row := sc.Text()
		result := strings.Split(strings.TrimSpace(row), ":")

		// We assume a count of 1. HIBP API sometimes responds without the
		// colon, so we just assume that the leak count is one.
		//
		// See https://github.com/ory/kratos/issues/2145

View on GitHub (pinned to b86338da04)