sipeed/picoclaw · error
reading device token response: %w
Error message
reading device token response: %w
What it means
pollDeviceCode (pkg/auth/oauth.go:422) received HTTP 200 from {Issuer}/api/accounts/deviceauth/token (meaning the user has approved) but io.ReadAll failed while streaming the token payload. The authorization code inside that body is lost, so the poll must be retried.
Source
Thrown at pkg/auth/oauth.go:422
})
resp, err := http.Post(
cfg.Issuer+"/api/accounts/deviceauth/token",
"application/json",
strings.NewReader(string(reqBody)),
)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("pending")
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading device token response: %w", err)
}
var tokenResp struct {
AuthorizationCode string `json:"authorization_code"`
CodeChallenge string `json:"code_challenge"`
CodeVerifier string `json:"code_verifier"`
}
if err := json.Unmarshal(body, &tokenResp); err != nil {
return nil, err
}
redirectURI := cfg.Issuer + "/deviceauth/callback"
return ExchangeCodeForTokens(cfg, tokenResp.AuthorizationCode, tokenResp.CodeVerifier, redirectURI)
}
func RefreshAccessToken(cred *AuthCredential, cfg OAuthProviderConfig) (*AuthCredential, error) {
if cred.RefreshToken == "" {
return nil, fmt.Errorf("no refresh token available")View on GitHub (pinned to 49183d7e8d)
Solutions
- Retry the poll: for device flows the server typically keeps the authorization available, the next poll re-POSTs and re-reads
- Inspect the wrapped error for 'unexpected EOF' vs 'context deadline exceeded' to pick truncation vs timeout
- Increase http.Client timeout if a custom short one is in use
- Check intermediary proxies for response-size or idle limits
Defensive patterns
Strategy: retry
Type guard
func isTokenBodyReadError(err error) bool {
return err != nil && strings.Contains(err.Error(), "reading device token response")
} Try / catch
cred, err := auth.PollDeviceCodeOnce(cfg, deviceAuthID, userCode)
if err != nil && isTokenBodyReadError(err) {
time.Sleep(interval)
cred, err = auth.PollDeviceCodeOnce(cfg, deviceAuthID, userCode)
} Prevention
- Treat body-read failures during polling as retriable 'pending', not fatal
- Keep poll intervals at the server-advised value to avoid truncation under load
- Use a client timeout comfortably larger than the largest expected token response
- Surface poll errors in logs even when retrying
When it happens
Trigger: Connection dropped or context canceled after status 200 but before body completion on the deviceauth/token POST; proxy truncation; very short client timeout on a slow response.
Common situations: Flaky VPN/wifi mid-flow; corporate proxy idle-killing the stream; rare relative to pending/parse paths. Note LoginDeviceCode swallows this error and retries on the next tick; only callers of PollDeviceCodeOnce see it directly.
Related errors
- reading token refresh response: %w
- reading token exchange response: %w
- error fetching models: %w
- read error response: %w
- read response: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/c854c06ac3623b56.
Report an issue: GitHub.