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
- Check network interception: log the raw body of the `/copilot_internal/v2/token` response
- 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>`
- If 401-like bodies arrive with ok status, redo the device-flow login to get a fresh GitHub token
- Bypass corporate proxies or add them to the allowlist for githubcopilot.com hosts
- 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
- Refresh Copilot tokens proactively before expires_at minus 5 minutes instead of letting them lapse
- Redo device-flow login on any unexpected token-endpoint payload; GitHub tokens expire/revocable
- Verify enterprise domain so `copilot-api.<domain>` / api hosts resolve correctly
- Allowlist githubcopilot.com hosts in proxies and inspect raw bodies when failures occur
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
- Invalid device code response
- Invalid Copilot token response fields
- No webSocketDebuggerUrl found in CDP version response from $
- ${response.status} ${response.statusText}: ${text}
- Invalid device code response fields
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/471aa61fc9d397ca.
Report an issue: GitHub.