netbirdio/netbird · error
an earlier read of the policy table has not returned
Error message
an earlier read of the policy table has not returned
What it means
errValidationUnavailable branch of the scheme-flow validation (middleware.go:581): the token belongs to an OIDC-method scheme, validation must go through the sessionValidator gRPC (ValidateSession, middleware.go:693-698), and that RPC errored. The client sees 502 'authentication service unavailable'; the scheme type is recorded in captured data.
Source
Thrown at client/internal/debug/nrpt_windows.go:74
// registryValue is a name and its rendered value, shared by the registry and
// policy table readers so both anonymize by value name the same way.
type registryValue struct {
name string
value string
}
// effectiveNRPTPolicies reads the effective NRPT table. The call is bounded
// because a WMI provider can block indefinitely and a debug bundle must not.
func effectiveNRPTPolicies() ([]nrptPolicyEntry, error) {
type result struct {
text string
err error
}
select {
case nrptQueryInFlight <- struct{}{}:
default:
return nil, errors.New("an earlier read of the policy table has not returned")
}
done := make(chan result, 1)
go func() {
// the slot is released here rather than by the caller, so a read that
// outlives the timeout holds it until the provider answers
defer func() { <-nrptQueryInFlight }()
text, err := nrptPolicyTableText()
done <- result{text: text, err: err}
}()
select {
case res := <-done:
if res.err != nil {
return nil, res.err
}
return parseNRPTPolicyTable(res.text), nilView on GitHub (pinned to 93e97f4bf1)
Solutions
- Restore management availability; verify from the proxy host that the management gRPC endpoint answers.
- Inspect the chained error after 'session validation unavailable' in the logs for dial/TLS/deadline specifics.
- Re-dial or restart the proxy if the gRPC channel did not recover after management came back.
- Alert on this 502 signature to catch proxy-management splits early.
Defensive patterns
Strategy: retry
Try / catch
// Same transient class as header-token 502: ValidateSession gRPC failed.
// Retry the token submission with backoff once management is reachable.
for i := 0; i < 3; i++ {
resp, err = client.PostForm(loginURL, vals)
if err == nil && resp.StatusCode != http.StatusBadGateway {
break
}
time.Sleep((1 << i) * time.Second)
} Prevention
- Sequence management restarts so at least one instance serves ValidateSession.
- Verify proxy-to-management mTLS certificates on both sides after rotation.
- Alert on 502 across OIDC domains as a management-outage signal.
- Retries are safe; the submitted credentials and token are unaffected.
When it happens
Trigger: Login form (or programmatic token submission) on an OIDC-schemed domain completes, but when the proxy calls management's ValidateSession the gRPC call fails: management down, deadline exceeded, connection refused, TLS failure.
Common situations: Same class as index 7: management restarts/outages, proxy-to-management network issues, cert rotation breaking mTLS; typically many simultaneous 502s across all OIDC domains.
Related errors
- client not started
- sync response is not available
- engine is not initialized
- sync response persistence is disabled
- %s %s
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/31333a6786595e2a.
Report an issue: GitHub.