sipeed/picoclaw · error
flow does not support polling
Error message
flow does not support polling
What it means
Returned as HTTP 400 by POST /api/oauth/flows/{id}/poll when the flow exists but its Method is not "device_code". Polling is implemented exclusively for the device-code grant; browser flows complete via the /oauth/callback redirect (which exchanges the code and marks the flow success), so there is nothing to poll. The check runs before the pending-status check, so even a completed browser flow hit with POST returns this 400.
Source
Thrown at web/backend/api/oauth.go:352
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(flowToResponse(flow))
}
func (h *Handler) handlePollOAuthFlow(w http.ResponseWriter, r *http.Request) {
flowID := strings.TrimSpace(r.PathValue("id"))
if flowID == "" {
http.Error(w, "missing flow id", http.StatusBadRequest)
return
}
flow, ok := h.getOAuthFlow(flowID)
if !ok {
http.Error(w, "flow not found", http.StatusNotFound)
return
}
if flow.Method != oauthMethodDeviceCode {
http.Error(w, "flow does not support polling", http.StatusBadRequest)
return
}
if flow.Status != oauthFlowPending {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(flowToResponse(flow))
return
}
cfg := auth.OpenAIOAuthConfig()
cred, err := oauthPollDeviceCodeOnce(cfg, flow.DeviceAuthID, flow.UserCode)
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "pending") {
updated, _ := h.getOAuthFlow(flowID)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(flowToResponse(updated))
return
}
h.setOAuthFlowError(flowID, fmt.Sprintf("device code poll failed: %v", err))View on GitHub (pinned to 49183d7e8d)
Solutions
- Only start a poll loop for flows created with method "device_code"; remember the method you used to create the flow.
- For browser flows, open the auth_url and wait for the /oauth/callback redirect (the page postMessages the result to the opener); use GET /api/oauth/flows/{id} to check status instead of POST poll.
- If the popup/callback failed, recover by GET /api/oauth/flows/{id} — do not POST poll, which will always 400 for browser flows.
Example fix
// before
const timer = setInterval(() => fetch(`/api/oauth/flows/${flowId}/poll`, {method:'POST'}), interval);
// browser flows -> 400 flow does not support polling
// after
if (method === 'device_code') {
setInterval(() => fetch(`/api/oauth/flows/${flowId}/poll`, {method:'POST'}), interval);
} else { // browser
setInterval(() => fetch(`/api/oauth/flows/${flowId}`), 2000);
} Defensive patterns
Strategy: validation
Validate before calling
function assertPollable(flow) {
if (flow?.method !== 'device_code') throw new Error('flow does not support polling');
return flow;
} Type guard
function isPollableFlow(flow) { return flow?.method === 'device_code'; } Prevention
- Branch on the method used at login: device_code → POST poll; browser → GET status and wait for the callback.
- Do not route browser flow ids into a generic poll loop.
When it happens
Trigger: POST /api/oauth/flows/<id>/poll where <id> was created by POST /api/oauth/login {"provider":"openai","method":"browser"} or {"provider":"google-antigravity","method":"browser"}. Any poll of a browser flow, pending or finished.
Common situations: Frontend using one generic poll loop for all login methods; refactoring that routes the browser flow's id into the device-code poller; polling a browser flow because the callback page never reached the opener (popup blocked).
Related errors
- provider %q does not support browser oauth
- missing flow id
- unsupported provider %q
- unsupported login method %q for provider %q
- token is required
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/dbd15c6556bc8429.
Report an issue: GitHub.