{"record":{"id":"fb81572474e14896","repo":"Wei-Shaw/sub2api","slug":"xai-device-flow-response-is-incomplete","errorCode":null,"errorMessage":"xAI device flow response is incomplete","messagePattern":"xAI device flow response is incomplete","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/internal/pkg/xai/sso_device.go","lineNumber":133,"sourceCode":"\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif status < 200 || status >= 300 {\n\t\treturn nil, fmt.Errorf(\"start xAI device flow: %w\", SSOHTTPError{Status: status})\n\t}\n\tvar device struct {\n\t\tDeviceCode              string `json:\"device_code\"`\n\t\tUserCode                string `json:\"user_code\"`\n\t\tVerificationURIComplete string `json:\"verification_uri_complete\"`\n\t\tInterval                int    `json:\"interval\"`\n\t\tExpiresIn               int    `json:\"expires_in\"`\n\t}\n\tif err := json.Unmarshal(body, &device); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse xAI device flow response: %w\", err)\n\t}\n\tif device.DeviceCode == \"\" || device.UserCode == \"\" || !safeXAIAuthURL(device.VerificationURIComplete) {\n\t\treturn nil, errors.New(\"xAI device flow response is incomplete\")\n\t}\n\tif device.Interval <= 0 {\n\t\tdevice.Interval = 5\n\t}\n\tif device.ExpiresIn <= 0 {\n\t\tdevice.ExpiresIn = 1800\n\t}\n\n\tstatus, _, _, err = f.do(ctx, http.MethodGet, device.VerificationURIComplete, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif status < 200 || status >= 400 {\n\t\treturn nil, fmt.Errorf(\"open xAI device verification page: %w\", SSOHTTPError{Status: status})\n\t}\n\n\tstatus, finalURL, _, err = f.do(ctx, http.MethodPost, SSOVerifyURL, url.Values{\"user_code\": {device.UserCode}})\n\tif err != nil {","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/pkg/xai/sso_device.go#L115-L151","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nif err := json.Unmarshal(body, &device); err != nil {\n    return nil, fmt.Errorf(\"parse xAI device flow response: %w\", err)\n}\nif device.DeviceCode == \"\" || device.UserCode == \"\" || !safeXAIAuthURL(device.VerificationURIComplete) {\n    return nil, errors.New(\"xAI device flow response is incomplete\")\n}\n\n// after (debugging aid: include a body excerpt in the error)\nconst sniff = 256\nexcerpt := string(body)\nif len(excerpt) > sniff { excerpt = excerpt[:sniff] }\nreturn nil, fmt.Errorf(\"xAI device flow response is incomplete (body starts: %s)\", excerpt)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var device *xai.DeviceCode\nerr := retry.Do(func() error {\n    var e error\n    device, e = flow.Start(ctx)\n    return e\n}, retry.RetryIf(func(e error) bool {\n    return errors.Is(e, xai.ErrDeviceFlowIncomplete) // transient schema/page hiccups\n}), retry.Attempts(2))","preventionTips":["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"],"tags":["xai","sso","device-flow","schema-drift"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}