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), nil

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Restore management availability; verify from the proxy host that the management gRPC endpoint answers.
  2. Inspect the chained error after 'session validation unavailable' in the logs for dial/TLS/deadline specifics.
  3. Re-dial or restart the proxy if the gRPC channel did not recover after management came back.
  4. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/31333a6786595e2a. Report an issue: GitHub.