sipeed/picoclaw · error

requesting device code: %w

Error message

requesting device code: %w

What it means

http.Post to {cfg.Issuer}/api/accounts/deviceauth/usercode failed at the transport level (oauth.go:262). No HTTP response was received: DNS resolution failed, TCP connect failed, TLS handshake failed, or the request timed out. Note the URL is the picoclaw/z.ai-style device-auth path — pointing cfg.Issuer at a standard OAuth issuer (e.g. Google) will never serve it (that surfaces as error 359 with a 404 body, not this one).

Source

Thrown at pkg/auth/oauth.go:262

	UserCode     string `json:"user_code"`
	VerifyURL    string `json:"verify_url"`
	Interval     int    `json:"interval"`
}

// RequestDeviceCode requests a device code from the OAuth provider.
// Returns the info needed for the user to authenticate in a browser.
func RequestDeviceCode(cfg OAuthProviderConfig) (*DeviceCodeInfo, error) {
	reqBody, _ := json.Marshal(map[string]string{
		"client_id": cfg.ClientID,
	})

	resp, err := http.Post(
		cfg.Issuer+"/api/accounts/deviceauth/usercode",
		"application/json",
		strings.NewReader(string(reqBody)),
	)
	if err != nil {
		return nil, fmt.Errorf("requesting device code: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("reading device code response: %w", err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("device code request failed: %s", string(body))
	}

	deviceResp, err := parseDeviceCodeResponse(body)
	if err != nil {
		return nil, fmt.Errorf("parsing device code response: %w", err)
	}

	if deviceResp.Interval < 1 {
		deviceResp.Interval = 5

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Reproduce the transport call: curl -v -X POST <Issuer>/api/accounts/deviceauth/usercode -H 'Content-Type: application/json' -d '{"client_id":"..."}'
  2. Fix DNS/proxy: verify the host resolves and HTTP(S)_PROXY points at a live proxy, or unset it
  3. Check cfg.Issuer spelling and scheme (no trailing slash, correct host)
  4. If TLS is the issue, install the corporate CA into the system trust store

Example fix

// before: issuer from a different provider's docs
cfg.Issuer = "https://accounts.google.com/o/oauth2/v2"

// after: issuer that actually serves the device-auth path
cfg.Issuer = "https://accounts.pico.ltd" // must expose /api/accounts/deviceauth/usercode
Defensive patterns

Strategy: retry

Validate before calling

// confirm the device-auth endpoint is reachable before starting the flow
func deviceEndpointReachable(issuer string) error {
    u := issuer + "/api/accounts/deviceauth/usercode"
    resp, err := http.Post(u, "application/json", strings.NewReader("{}"))
    if err != nil { return fmt.Errorf("unreachable: %w", err) }
    _ = resp.Body.Close()
    return nil // any HTTP answer means transport is fine
}

Try / catch

err := retryN(2, time.Second, func() error {
    _, e := auth.RequestDeviceCode(cfg)
    if e != nil && strings.Contains(e.Error(), "requesting device code") {
        return e // transport-level: retry
    }
    return retryStop{e}
})

Prevention

When it happens

Trigger: Calling RequestDeviceCode with no internet; DNS for cfg.Issuer failing; self-signed/wrong CA blocking TLS; HTTP(S)_PROXY env routing the request into a dead proxy; Issuer with a trailing slash or typo producing an unresolvable host.

Common situations: Air-gapped or proxied CI environments; cfg.Issuer copied from a different provider's docs; corporate MITM CA not in the trust store.

Related errors


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