Wei-Shaw/sub2api · error
xAI device flow response is incomplete
Error message
xAI device flow response is incomplete
What it means
Returned by the xAI SSO device flow when the initial POST to the device authorization endpoint yields a 200-ish body that either fails to deserialize or is missing required fields: device_code, user_code, or a safe verification_uri_complete. The flow cannot continue without all three because the subsequent verify/approve steps key off them.
Source
Thrown at backend/internal/pkg/xai/sso_device.go:133
})
if err != nil {
return nil, err
}
if status < 200 || status >= 300 {
return nil, fmt.Errorf("start xAI device flow: %w", SSOHTTPError{Status: status})
}
var device struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURIComplete string `json:"verification_uri_complete"`
Interval int `json:"interval"`
ExpiresIn int `json:"expires_in"`
}
if err := json.Unmarshal(body, &device); err != nil {
return nil, fmt.Errorf("parse xAI device flow response: %w", err)
}
if device.DeviceCode == "" || device.UserCode == "" || !safeXAIAuthURL(device.VerificationURIComplete) {
return nil, errors.New("xAI device flow response is incomplete")
}
if device.Interval <= 0 {
device.Interval = 5
}
if device.ExpiresIn <= 0 {
device.ExpiresIn = 1800
}
status, _, _, err = f.do(ctx, http.MethodGet, device.VerificationURIComplete, nil)
if err != nil {
return nil, err
}
if status < 200 || status >= 400 {
return nil, fmt.Errorf("open xAI device verification page: %w", SSOHTTPError{Status: status})
}
status, finalURL, _, err = f.do(ctx, http.MethodPost, SSOVerifyURL, url.Values{"user_code": {device.UserCode}})
if err != nil {View on GitHub (pinned to 073e92d171)
Solutions
- Capture the raw response body (temporarily log it) and compare against the expected {device_code, user_code, verification_uri_complete} shape.
- Retry once after a short delay to rule out a transient page/interstitial.
- If the schema genuinely changed, update the device struct field names/tags in sso_device.go.
- Bypass any corporate proxy for accounts.x.ai / xai.com OAuth hosts.
Example fix
// before
if err := json.Unmarshal(body, &device); err != nil {
return nil, fmt.Errorf("parse xAI device flow response: %w", err)
}
if device.DeviceCode == "" || device.UserCode == "" || !safeXAIAuthURL(device.VerificationURIComplete) {
return nil, errors.New("xAI device flow response is incomplete")
}
// after (debugging aid: include a body excerpt in the error)
const sniff = 256
excerpt := string(body)
if len(excerpt) > sniff { excerpt = excerpt[:sniff] }
return nil, fmt.Errorf("xAI device flow response is incomplete (body starts: %s)", excerpt) Defensive patterns
Strategy: retry
Try / catch
var device *xai.DeviceCode
err := retry.Do(func() error {
var e error
device, e = flow.Start(ctx)
return e
}, retry.RetryIf(func(e error) bool {
return errors.Is(e, xai.ErrDeviceFlowIncomplete) // transient schema/page hiccups
}), retry.Attempts(2)) Prevention
- Pin tests to recorded response fixtures so schema drift is caught in CI
- Log body excerpts on this error
- Keep the device struct fields in sync with xAI's response via a contract test
When it happens
Trigger: xAI changes or breaks its device authorization response schema (renames fields, returns an HTML error page with 200, or returns an empty object); or a MITM/proxy rewrites the response. JSON that parses but lacks any of the three required fields triggers this exact error.
Common situations: xAI ships an API change to the undocumented device-flow endpoint; Cloudflare interstitials returning HTML; corporate proxies mangling responses; regional variants of the auth host serving a different payload.
Related errors
- xAI device verification did not reach consent page
- xAI device approval did not reach done page
- xAI device flow token polling timed out
- xai sso unauthorized
- xAI OAuth response exceeds 2 MiB
AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15).
Data as JSON: /api/errors/fb81572474e14896.
Report an issue: GitHub.