mastra-ai/mastra · error

Invalid Copilot token response

Error message

Invalid Copilot token response

What it means

`refreshGitHubCopilotToken` exchanges the stored GitHub OAuth token for a Copilot bearer token at `https://api.<domain>/copilot_internal/v2/token`. If the response is ok but not a JSON object (or empty), the SDK throws this error before extracting `token`/`expires_at`. It signals the Copilot internal token endpoint returned an unexpected payload.

Source

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

  signal?: AbortSignal,
): Promise<GitHubCopilotCredentials> {
  const domain = enterpriseDomain || 'github.com';
  const urls = getUrls(domain);

  const raw = await fetchJson(
    urls.copilotTokenUrl,
    {
      headers: {
        Accept: 'application/json',
        Authorization: `Bearer ${refreshToken}`,
        ...COPILOT_HEADERS,
      },
    },
    signal,
  );

  if (!raw || typeof raw !== 'object') {
    throw new Error('Invalid Copilot token response');
  }

  const obj = raw as Record<string, unknown>;
  const token = obj.token;
  const expiresAt = obj.expires_at;

  if (typeof token !== 'string' || typeof expiresAt !== 'number') {
    throw new Error('Invalid Copilot token response fields');
  }

  const credentials: GitHubCopilotCredentials = {
    refresh: refreshToken,
    access: token,
    // expires_at is seconds; subtract 5 minutes so we refresh before actual expiry.
    expires: expiresAt * 1000 - 5 * 60 * 1000,
  };
  if (enterpriseDomain) {
    credentials.enterpriseUrl = enterpriseDomain;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check network interception: log the raw body of the `/copilot_internal/v2/token` response
  2. Verify the Copilot API base URL resolution — with no `proxy-ep` in the token it falls back to `https://api.individual.githubcopilot.com` or `https://copilot-api.<enterpriseDomain>`
  3. If 401-like bodies arrive with ok status, redo the device-flow login to get a fresh GitHub token
  4. Bypass corporate proxies or add them to the allowlist for githubcopilot.com hosts
  5. Update the SDK if GitHub changed the internal token endpoint response envelope

Example fix

// before: refresh against an unverifiable host
const creds = await refreshGitHubCopilotToken(githubToken); // throws 'Invalid Copilot token response'
// after: verify the endpoint returns the expected envelope first
const res = await fetch('https://api.individual.githubcopilot.com/copilot_internal/v2/token', { headers: { Authorization: `token ${githubToken}` } });
const body = await res.json();
console.log(res.status, typeof body, Object.keys(body)); // expect { token: string, expires_at: number }
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify your GitHub token and the endpoint before refreshing
function copilotApiHost(enterpriseDomain?: string): string {
  return enterpriseDomain ? `https://copilot-api.${enterpriseDomain}` : 'https://api.individual.githubcopilot.com';
}
if (!githubToken || githubToken.length < 20) throw new Error('GitHub OAuth token missing/invalid — redo device flow before refreshing Copilot token');

Type guard

function isCopilotTokenResponse(v: unknown): v is { token: string; expires_at: number } {
  return !!v && typeof v === 'object' && typeof (v as Record<string, unknown>).token === 'string' && typeof (v as Record<string, unknown>).expires_at === 'number';
}

Try / catch

try {
  const creds = await provider.refreshToken();
} catch (e) {
  if (e instanceof Error && e.message === 'Invalid Copilot token response') {
    console.error('Copilot token endpoint returned a non-object body — check enterprise domain config and proxies', e.message);
    return startFreshDeviceFlow(); // stale/revoked GitHub token often the cause
  }
  throw e;
}

Prevention

When it happens

Trigger: The Copilot token endpoint returned 200 with an empty/array/string body, or a gateway/proxy responded with ok but non-token JSON. Common with a wrong enterprise domain producing an unexpected api host (`copilot-api.<enterpriseDomain>`), or a proxy intercepting `api.individual.githubcopilot.com`.

Common situations: Expired/revoked GitHub OAuth token causing a non-standard body, GHE instances where `copilot_internal` endpoints behave differently, misconfigured enterprise domain, corporate proxies/CDNs replacing the response.

Related errors


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