sipeed/picoclaw · critical

failed to generate state: %v

Error message

failed to generate state: %v

What it means

Returned as HTTP 500 by POST /api/oauthLogin (browser method) when auth.GenerateState fails. GenerateState reads 32 bytes from crypto/rand and hex-encodes them; like the PKCE failure, it only fails when the system CSPRNG is inaccessible. It is the same class of environmental failure as error 966, one call later in the same handler.

Source

Thrown at web/backend/api/oauth.go:284

			"expires_at": flow.ExpiresAt.Format(time.RFC3339),
		})
		return

	case oauthMethodBrowser:
		cfg, err := oauthConfigForProvider(provider)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		pkce, err := oauthGeneratePKCE()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to generate PKCE: %v", err), http.StatusInternalServerError)
			return
		}
		state, err := oauthGenerateState()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to generate state: %v", err), http.StatusInternalServerError)
			return
		}

		redirectURI := buildOAuthRedirectURI(r)
		authURL := oauthBuildAuthorizeURL(cfg, pkce, state, redirectURI)

		now := oauthNow()
		flow := &oauthFlow{
			ID:           newOAuthFlowID(),
			Provider:     provider,
			Method:       method,
			Status:       oauthFlowPending,
			CreatedAt:    now,
			UpdatedAt:    now,
			ExpiresAt:    now.Add(oauthBrowserFlowTTL),
			CodeVerifier: pkce.CodeVerifier,
			OAuthState:   state,
			RedirectURI:  redirectURI,

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Test the CSPRNG in the backend's exact environment (a Go one-liner with crypto/rand or reading /dev/urandom).
  2. Fix the sandbox/kernel (allow getrandom, add virtio-rng to the VM, mount /dev properly) and retry the browser login.
  3. Treat repeated occurrences as an infrastructure incident: this error means the host cannot generate secure randomness at all, which breaks every auth path, not just this one.
  4. Workaround for users: complete login with method "token" if available for the provider (openai, anthropic).
Defensive patterns

Strategy: fallback

Try / catch

const res = await startBrowserLogin(provider);
if (res.status === 500 && /generate state/i.test((await res.json()).message ?? '')) {
  return startTokenLogin(provider); // CSPRNG unavailable — use a method that needs no rand
}
return res;

Prevention

When it happens

Trigger: POST /api/oauth/login {"provider":"openai","method":"browser"} on a runtime where crypto/rand.Read errors (seccomp-blocked getrandom, early-boot entropy starvation, broken /dev/urandom). If PKCE succeeded but this fails, the entropy source died between the two calls.

Common situations: Hardened container runtimes, VMs without RNG devices, chroot environments without /dev mounted properly.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/969de6e4a97910ae. Report an issue: GitHub.