{"record":{"id":"89226b588d2c17af","repo":"router-for-me/CLIProxyAPI","slug":"xai-device-code-response-missing-device-code","errorCode":null,"errorMessage":"xai device code: response missing device_code","messagePattern":"xai device code: response missing device_code","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/xai/xai.go","lineNumber":166,"sourceCode":"\t\tif errClose := resp.Body.Close(); errClose != nil {\n\t\t\tlog.Errorf(\"xai device code: close response body error: %v\", errClose)\n\t\t}\n\t}()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"xai device code: read response: %w\", err)\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"xai device code request failed with status %d: %s\", resp.StatusCode, strings.TrimSpace(string(body)))\n\t}\n\n\tvar deviceCode DeviceCodeResponse\n\tif err = json.Unmarshal(body, &deviceCode); err != nil {\n\t\treturn nil, fmt.Errorf(\"xai device code: parse response: %w\", err)\n\t}\n\tif strings.TrimSpace(deviceCode.DeviceCode) == \"\" {\n\t\treturn nil, fmt.Errorf(\"xai device code: response missing device_code\")\n\t}\n\tif strings.TrimSpace(deviceCode.UserCode) == \"\" {\n\t\treturn nil, fmt.Errorf(\"xai device code: response missing user_code\")\n\t}\n\tif strings.TrimSpace(deviceCode.VerificationURI) == \"\" && strings.TrimSpace(deviceCode.VerificationURIComplete) == \"\" {\n\t\treturn nil, fmt.Errorf(\"xai device code: response missing verification URI\")\n\t}\n\tdeviceCode.TokenEndpoint = strings.TrimSpace(tokenEndpoint)\n\treturn &deviceCode, nil\n}\n\n// WaitForAuthorization polls until the user authorizes the device code and returns tokens.\nfunc (a *XAIAuth) WaitForAuthorization(ctx context.Context, deviceCode *DeviceCodeResponse) (*AuthBundle, error) {\n\ttokenData, err := a.PollForToken(ctx, deviceCode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttokenEndpoint := \"\"","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/xai/xai.go#L148-L184","documentation":"The xAI device-authorization endpoint returned HTTP 200 with valid JSON, but the parsed DeviceCodeResponse has an empty device_code field. The code in internal/auth/xai/xai.go treats device_code as mandatory because the whole poll loop (PollForToken/exchangeDeviceCode) sends it back as the grant credential. This error means the server agreed to start a device flow yet did not hand back the code that identifies it.","triggerScenarios":"A successful POST to the xAI device authorization endpoint whose JSON body omits device_code or contains only whitespace (e.g. {\"user_code\":\"ABCD\",\"verification_uri\":\"...\"} or an empty object {}).","commonSituations":"xAI changed its device-authorization response schema; the request hit a wrong or proxy-mangled endpoint that returns 200 with an HTML/empty body; client_id (ClientID constant) was not registered for the device flow so the server returns a 200 error payload missing the field.","solutions":["Log the raw response body before unmarshalling and re-run the auth to see exactly what the endpoint returned","Verify the device authorization URL and token endpoint against current xAI/OAuth discovery documents (a.Discover output)","Confirm the ClientID constant still matches an xAI application allowed to use the device code grant","If xAI renamed the field, update the DeviceCodeResponse json tags in internal/auth/xai/xai.go accordingly"],"exampleFix":"// before\nif strings.TrimSpace(deviceCode.DeviceCode) == \"\" {\n    return nil, fmt.Errorf(\"xai device code: response missing device_code\")\n}\n\n// after (keep the guard, but surface the payload for diagnosis)\nif strings.TrimSpace(deviceCode.DeviceCode) == \"\" {\n    return nil, fmt.Errorf(\"xai device code: response missing device_code: body=%s\", strings.TrimSpace(string(body)))\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := auth.RequestDeviceCode(ctx); err != nil {\n    if strings.Contains(err.Error(), \"response missing device_code\") {\n        log.Errorf(\"xAI device endpoint returned an unexpected payload; check endpoint and client_id: %v\", err)\n    }\n    return err\n}","preventionTips":["Pin and verify discovery endpoints before starting the device flow","Keep the ClientID constant in sync with the xAI app registration","In tests, mock the device authorization endpoint with a fully-populated RFC 8628 response"],"tags":["oauth","device-flow","xai","auth","response-validation"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}