Skip to main content
The SDK distinguishes between two classes of failures:
  1. Initial sync failures - surfaced as a non-nil error from NewClient. Refuse to start the application; an empty cache is unsafe to serve.
  2. Background sync / SSE failures - never returned to the caller. They are logged via Logger.Errorf(...), and the existing cache continues to be served.

Sentinel errors

The SDK exports the following sentinel error variables. Always check with errors.Is(err, ...) rather than equality or string matching:
This is idiomatic Go - sentinel errors compose cleanly with errors.Is and errors.As, and they’re the way io.EOF, os.ErrNotExist, sql.ErrNoRows, etc. work in the standard library.

When each is returned

What is NOT returned as an error

  • Background syncs - silently retried on the next TTL tick. Cache served.
  • SSE transport errors - exponential backoff, 3-strike fallback to polling. RunStream returns normally.
  • 304 Not Modified - treated as success; TTL reset.
  • Missing config / flag - GetConfig returns (nil, false); GetFlag returns the defaultValue.
The asymmetry between secrets (return error) and configs/flags (return ok/default) is deliberate: a missing secret usually means “you’re misconfigured, fail fast”, while a missing flag usually means “use the safe default and continue”.

402 Payment Required - ErrBilling

When the backend returns HTTP 402 (the tenant has at least one invoice overdue by more than 14 days), the SDK:
  1. Marks the client’s billing-overdue flag (client.BillingOverdue() == true).
  2. Halts the background refresh loop - read methods continue to serve the last cached snapshot.
  3. Returns ErrBilling from Sync(...).
The flag clears automatically as soon as a subsequent Sync succeeds.

WIF-specific errors

When WIFConfig.Enabled is true:
  • ErrWIFNotConfigured - the configured (or auto-detected) provider isn’t usable in the current environment. Either the K8s service-account token file is missing, the AWS_WEB_IDENTITY_TOKEN_FILE env var isn’t set, or the GCP/Azure metadata endpoint isn’t reachable. Pass an explicit TokenSource to bypass auto-detection.
  • ErrWIFTokenExchangeFailed - the backend rejected the OIDC token, or the response could not be decoded. Inspect the wrapped error for the HTTP status. Most often caused by an audience mismatch or a clock skew between the provider and the Nexus backend.
  • ErrSessionExpired - only fires when a refresh attempt fails AND no static APIKey fallback is configured. Provide both WIF and APIKey if you need automatic fallback in degraded conditions.

ErrServiceKindMismatch (frontend services)

GetSecret(...) on a service whose kind is "frontend" returns ErrServiceKindMismatch. Check client.Kind() to know the kind:

Failure scenarios

Wrong API key

ErrSyncFailed is the outer error; the cause is wrapped - errors.Is(err, nexus.ErrUnauthorized) matches transitively.

Slug doesn’t match key (Double-Gate failure)

In production, the backend validates that the slug embedded in BaseURL matches the API key’s service. A mismatch returns 401 - same surface as above.

Network down at startup

If the Nexus backend is unreachable when NewClient runs, the function returns an error wrapping ErrSyncFailed whose cause is a *url.Error. The decision is yours: crash, or wrap with retry/backoff.

Reading a secret with a public key

This check fires synchronously, before the network call.

Reading a secret that doesn’t exist

SSE-specific behaviour

RunStream failures never propagate to your code as errors. The SDK logs them at Errorf level and returns when:
  • The context is cancelled (clean shutdown)
  • 3 consecutive transport errors exhaust the backoff (silent fallback)
If you need to detect “live updates are no longer available”, launch RunStream with a done channel and check whether it returned before ctx.Done():