decolua/9router · error

xai discovery ${field} is empty

Error message

xai discovery ${field} is empty

What it means

validateOAuthEndpoint in the xAI OAuth service validates a discovery URL field (e.g. authorization or token endpoint obtained from xAI's discovery document). It throws this when the raw value is missing, empty, or whitespace-only after trimming. Discovery-driven flows cannot proceed without concrete endpoint URLs.

Source

Thrown at src/lib/oauth/services/xai.js:28

 * xAI (Grok) OAuth Service
 *
 * Source of truth: router-for-me/CLIProxyAPI internal/auth/xai/xai.go
 *
 * Flow:
 *  1. Discover endpoints from `${XAI_ISSUER}/.well-known/openid-configuration`
 *  2. Bind loopback server on 127.0.0.1:56121, path /callback
 *  3. PKCE S256 with 96-byte verifier
 *  4. Exchange code with form-urlencoded body
 *  5. id_token email decode (no signature verify, mirrors Go)
 */

const BASE64_BLOCK_SIZE = 4;

let cachedDiscovery = null;

export function validateOAuthEndpoint(rawUrl, field) {
  const value = String(rawUrl || "").trim();
  if (!value) throw new Error(`xai discovery ${field} is empty`);

  let parsed;
  try {
    parsed = new URL(value);
  } catch (err) {
    throw new Error(`xai discovery ${field} is invalid: ${err.message}`);
  }

  if (parsed.protocol !== "https:") {
    throw new Error(`xai discovery ${field} must use https: ${value}`);
  }

  const host = parsed.hostname.toLowerCase().trim();
  if (host !== "x.ai" && !host.endsWith(".x.ai")) {
    throw new Error(`xai discovery ${field} host ${host} is not on x.ai`);
  }

  return value;

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Check which 'field' the error names and set that URL explicitly in config/env.
  2. Re-fetch the discovery document from https://x.ai/.well-known/... and confirm the field is present.
  3. Clear any stale cached discovery data (the service caches discovery results).
  4. Verify you're not passing an empty string where a URL constant was intended.

Example fix

// before
const endpoints = discoverEndpoints({});
// after
const endpoints = discoverEndpoints({ authorizationUrl: process.env.XAI_AUTH_URL, tokenUrl: process.env.XAI_TOKEN_URL });
Defensive patterns

Strategy: validation

Validate before calling

const required = { authorizationUrl: cfg.authorizationUrl, tokenUrl: cfg.tokenUrl };
for (const [k, v] of Object.entries(required)) {
  if (!v || !String(v).trim()) throw new Error(`xAI config: ${k} is not set`);
}

Type guard

function hasEndpoint(u) {
  return typeof u === 'string' && u.trim().length > 0;
}

Prevention

When it happens

Trigger: discoverEndpoints receives a discovery document where the expected field is absent/empty — e.g. xAI's well-known response omits a field, or config/env supplying the URL is unset ('' or undefined).

Common situations: Missing XAI_* env vars; xAI changing its OIDC discovery document shape; a partial/cached discovery document stored from a failed fetch.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/3c415ed41fa6e17d. Report an issue: GitHub.