vxcontrol/pentagi · error

could not create Google OpenID client: %w

Error message

could not create Google OpenID client: %w

What it means

Inside newGoogleEmailResolver (backend/pkg/server/oauth/google.go:22), oidc.NewProvider fetches Google's OpenID Connect discovery document from https://accounts.google.com. If that HTTP discovery request fails, the error is wrapped as "could not create Google OpenID client" and the email resolver aborts before any token is inspected.

Source

Thrown at backend/pkg/server/oauth/google.go:22

	"context"
	"fmt"

	"github.com/coreos/go-oidc/v3/oidc"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

type googleTokenClaims struct {
	Nonce         string `json:"nonce"`
	Email         string `json:"email"`
	EmailVerified bool   `json:"email_verified"`
}

func newGoogleEmailResolver(clientID string) OAuthEmailResolver {
	return func(ctx context.Context, nonce string, token *oauth2.Token) (string, bool, error) {
		provider, err := oidc.NewProvider(ctx, "https://accounts.google.com")
		if err != nil {
			return "", false, fmt.Errorf("could not create Google OpenID client: %w", err)
		}

		oidToken, ok := token.Extra("id_token").(string)
		if !ok {
			return "", false, fmt.Errorf("id_token is not present in the token")
		}

		verifier := provider.Verifier(&oidc.Config{ClientID: clientID})
		idToken, err := verifier.Verify(ctx, oidToken)
		if err != nil {
			return "", false, fmt.Errorf("could not verify Google ID Token: %w", err)
		}

		if idToken.Nonce != nonce {
			return "", false, fmt.Errorf("nonce mismatch in Google ID Token")
		}

		if err = idToken.VerifyAccessToken(token.AccessToken); err != nil {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Restore outbound HTTPS connectivity to https://accounts.google.com from the backend (proxy/firewall/DNS).
  2. If a proxy is required, configure HTTPS_PROXY for the process.
  3. Cache the OIDC provider (create it once at startup) instead of per-request to reduce discovery calls and surface config issues early.
  4. Retry the login if the failure was transient.

Example fix

// before (per request)
provider, err := oidc.NewProvider(ctx, "https://accounts.google.com")

// after (once at startup)
var googleProvider *oidc.Provider
func initGoogleOIDC(ctx context.Context) error {
    p, err := oidc.NewProvider(ctx, "https://accounts.google.com")
    if err != nil {
        return err
    }
    googleProvider = p
    return nil
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight reachability of Google's OIDC discovery document
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://accounts.google.com/.well-known/openid-configuration", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
    return fmt.Errorf("Google OIDC discovery unreachable (check egress/proxy/DNS): %w", err)
}
resp.Body.Close()

Try / catch

email, verified, err := googleEmailResolver(ctx, nonce, token)
if err != nil {
    var ue *url.Error
    if errors.As(err, &ue) || strings.Contains(err.Error(), "could not create Google OpenID client") {
        return "", false, fmt.Errorf("sign-in temporarily unavailable (cannot reach Google); retry")
    }
    return "", false, err
}

Prevention

When it happens

Trigger: Any callback-time invocation where oidc.NewProvider cannot reach or parse the discovery document: network/DNS failure, blocked egress, TLS interception, or Google returning a non-200/error response.

Common situations: Backend running in an air-gapped or firewalled environment without access to accounts.google.com; corporate proxy with TLS re-signing; Docker/Compose network without outbound internet; transient Google outage during login.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/8d615fcd19e72839. Report an issue: GitHub.