mastra-ai/mastra · error

${response.status} ${response.statusText}: ${text}

Error message

${response.status} ${response.statusText}: ${text}

What it means

This is the generic HTTP failure thrown by the SDK's GitHub Copilot auth `fetchJson` helper whenever the GitHub OAuth/device-code or Copilot token endpoint returns a non-2xx response. The message embeds the HTTP status, status text, and the raw response body, so it directly reflects what the GitHub server rejected. It surfaces during device-flow login (`startDeviceFlow`, token polling) and Copilot bearer-token refresh.

Source

Thrown at mastracode/sdk/src/auth/providers/github-copilot.ts:114

/**
 * Resolve the Copilot API base URL.
 * Prefers the `proxy-ep` parsed from the bearer token, then falls back to enterprise/individual defaults.
 */
export function getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {
  if (token) {
    const fromToken = getBaseUrlFromToken(token);
    if (fromToken) return fromToken;
  }
  if (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;
  return 'https://api.individual.githubcopilot.com';
}

async function fetchJson(url: string, init: RequestInit, signal?: AbortSignal): Promise<unknown> {
  const response = await fetch(url, signal ? { ...init, signal } : init);
  if (!response.ok) {
    const text = await response.text().catch(() => '');
    throw new Error(`${response.status} ${response.statusText}: ${text}`);
  }
  return response.json();
}

async function startDeviceFlow(domain: string, signal?: AbortSignal): Promise<DeviceCodeResponse> {
  const urls = getUrls(domain);
  const data = await fetchJson(
    urls.deviceCodeUrl,
    {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': COPILOT_USER_AGENT,
      },
      body: new URLSearchParams({
        client_id: CLIENT_ID,
        scope: 'read:user',

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the status and body in the message: `authorization_pending`/`slow_down` bodies mean keep polling — ensure your caller tolerates these instead of crashing
  2. Verify the configured GitHub domain (github.com vs your GHES hostname) — a wrong domain produces 404/SSL errors
  3. Check network/proxy reachability to github.com and api.github.com and retry 5xx/429 with backoff
  4. If 401/403 on the Copilot token endpoint, redo the full device-flow login to obtain a fresh GitHub OAuth token
  5. Confirm the SDK's client_id/endpoint config matches the installed version if the API contract changed

Example fix

// before: treating every non-ok response as fatal, even during polling
const creds = await provider.device(); // throws on authorization_pending
// after: catch and branch on the pending/slow-down bodies
try {
  const creds = await provider.device();
} catch (e) {
  const m = String((e as Error).message);
  if (m.includes('authorization_pending') || m.includes('slow_down')) {
    await sleep(intervalMs);
    return; // keep polling
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Precheck connectivity and domain before calling the provider
async function canReach(url: string): Promise<boolean> {
  try { const r = await fetch(url, { method: 'HEAD' }); return r.status < 500 || r.status !== 404; } catch { return false; }
}
await canReach('https://github.com/login/device/code');

Type guard

function isHttpErrorWithStatus(e: unknown): e is Error & { message: string } {
  return e instanceof Error && /^\d{3} /.test(e.message);
}
function parseStatus(msg: string): number | null {
  const m = /^(\d{3}) /.exec(msg);
  return m ? Number(m[1]) : null;
}

Try / catch

try {
  const creds = await provider.device();
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  const status = parseStatus(msg);
  if (status === 429 || (status ?? 500) >= 500) { await backoff(); return retry(); }
  if (msg.includes('authorization_pending') || msg.includes('slow_down')) { await sleep(intervalMs); return; }
  if (status === 401 || status === 403) { return startFreshDeviceFlow(); }
  throw e;
}

Prevention

When it happens

Trigger: Any non-ok response from `POST https://github.com/login/device/code`, `POST .../login/oauth/access_token`, or `POST https://api.<domain>/copilot_internal/v2/token` — e.g. 401 after the user denied the device flow, 400 from a wrong `client_id` or malformed body, 404/redirect from an incorrect enterprise domain, 429 slow-down during polling, 5xx from GitHub.

Common situations: Polling `access_token` before the user finishes entering the device code (expected `authorization_pending` 400s surfaced as this error if not handled), misconfigured GHES/GHE domain so URLs point at the wrong host, expired or revoked GitHub OAuth grant during token refresh, corporate proxy or rate limiting returning 403/429.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/5ea8b9b48d325bc4. Report an issue: GitHub.