Files
openclaw/extensions/github-copilot/token-exchange-error.ts
Dallin Romney c3c665f7f6 fix: make Copilot token exchange 403 errors actionable (#112025)
* fix: explain GitHub Copilot 403 recovery

* fix: keep control UI log hint internal

* fix: clarify log viewing hint
2026-07-21 17:11:25 +09:00

41 lines
1.5 KiB
TypeScript

// GitHub Copilot token exchange errors shared by runtime and fallback policy.
type CopilotTokenExchangeFailure =
| { reason: "http_error"; status: number }
| { reason: "timeout"; timeoutMs: number; cause?: unknown };
function buildCopilotTokenExchangeMessage(failure: CopilotTokenExchangeFailure): string {
if (failure.reason === "timeout") {
return `Copilot token exchange failed: timed out after ${failure.timeoutMs}ms`;
}
const message = `Copilot token exchange failed: HTTP ${failure.status}`;
if (failure.status !== 403) {
return message;
}
return (
`${message}. Run \`openclaw models auth login-github-copilot\` in a terminal to ` +
"authenticate again. If this still fails, verify that your GitHub account has Copilot " +
"access and that your organization or enterprise policy permits it."
);
}
export class CopilotTokenExchangeError extends Error {
readonly code = "github_copilot_token_exchange_failed";
readonly reason: CopilotTokenExchangeFailure["reason"];
readonly status?: number;
readonly timeoutMs?: number;
constructor(failure: CopilotTokenExchangeFailure) {
super(
buildCopilotTokenExchangeMessage(failure),
failure.reason === "timeout" ? { cause: failure.cause } : undefined,
);
this.name = "CopilotTokenExchangeError";
this.reason = failure.reason;
if (failure.reason === "http_error") {
this.status = failure.status;
} else {
this.timeoutMs = failure.timeoutMs;
}
}
}