router-for-me/CLIProxyAPI · error

xai device code: response missing device_code

Error message

xai device code: response missing device_code

What it means

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.

Source

Thrown at internal/auth/xai/xai.go:166

		if errClose := resp.Body.Close(); errClose != nil {
			log.Errorf("xai device code: close response body error: %v", errClose)
		}
	}()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("xai device code: read response: %w", err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("xai device code request failed with status %d: %s", resp.StatusCode, strings.TrimSpace(string(body)))
	}

	var deviceCode DeviceCodeResponse
	if err = json.Unmarshal(body, &deviceCode); err != nil {
		return nil, fmt.Errorf("xai device code: parse response: %w", err)
	}
	if strings.TrimSpace(deviceCode.DeviceCode) == "" {
		return nil, fmt.Errorf("xai device code: response missing device_code")
	}
	if strings.TrimSpace(deviceCode.UserCode) == "" {
		return nil, fmt.Errorf("xai device code: response missing user_code")
	}
	if strings.TrimSpace(deviceCode.VerificationURI) == "" && strings.TrimSpace(deviceCode.VerificationURIComplete) == "" {
		return nil, fmt.Errorf("xai device code: response missing verification URI")
	}
	deviceCode.TokenEndpoint = strings.TrimSpace(tokenEndpoint)
	return &deviceCode, nil
}

// WaitForAuthorization polls until the user authorizes the device code and returns tokens.
func (a *XAIAuth) WaitForAuthorization(ctx context.Context, deviceCode *DeviceCodeResponse) (*AuthBundle, error) {
	tokenData, err := a.PollForToken(ctx, deviceCode)
	if err != nil {
		return nil, err
	}
	tokenEndpoint := ""

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Log the raw response body before unmarshalling and re-run the auth to see exactly what the endpoint returned
  2. Verify the device authorization URL and token endpoint against current xAI/OAuth discovery documents (a.Discover output)
  3. Confirm the ClientID constant still matches an xAI application allowed to use the device code grant
  4. If xAI renamed the field, update the DeviceCodeResponse json tags in internal/auth/xai/xai.go accordingly

Example fix

// before
if strings.TrimSpace(deviceCode.DeviceCode) == "" {
    return nil, fmt.Errorf("xai device code: response missing device_code")
}

// after (keep the guard, but surface the payload for diagnosis)
if strings.TrimSpace(deviceCode.DeviceCode) == "" {
    return nil, fmt.Errorf("xai device code: response missing device_code: body=%s", strings.TrimSpace(string(body)))
}
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := auth.RequestDeviceCode(ctx); err != nil {
    if strings.Contains(err.Error(), "response missing device_code") {
        log.Errorf("xAI device endpoint returned an unexpected payload; check endpoint and client_id: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: 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 {}).

Common situations: 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.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/89226b588d2c17af. Report an issue: GitHub.