can1357/oh-my-pi · error · AIError.OAuthError
GitLab Duo Workflow OAuth refresh failed: ${response.status}
Error message
GitLab Duo Workflow OAuth refresh failed: ${response.status} ${await response.text()} What it means
refreshGitLabDuoWorkflowToken POSTs a refresh_token grant to https://gitlab.com/oauth/token using GitLab's VS Code Workflow client id and the vscode:// redirect URI. When GitLab responds with a non-2xx status, this OAuthError is thrown with the HTTP status and the raw response body embedded in the message. It means the stored refresh token could no longer be exchanged for a new access token.
Source
Thrown at packages/ai/src/registry/oauth/gitlab-duo-workflow.ts:128
}
export async function refreshGitLabDuoWorkflowToken(
credentials: OAuthCredentials,
fetchImpl: FetchImpl = fetch,
): Promise<OAuthCredentials> {
const response = await fetchImpl(`${GITLAB_COM_URL}/oauth/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
client_id: GITLAB_DUO_WORKFLOW_OAUTH_CLIENT_ID,
redirect_uri: GITLAB_DUO_WORKFLOW_OAUTH_REDIRECT_URI,
grant_type: "refresh_token",
refresh_token: credentials.refresh,
}).toString(),
});
if (!response.ok) {
throw new AIError.OAuthError(
`GitLab Duo Workflow OAuth refresh failed: ${response.status} ${await response.text()}`,
{
kind: "token-refresh",
provider: "gitlab-duo-workflow",
status: response.status,
},
);
}
return mapTokenResponse(
(await response.json()) as {
access_token?: string;
refresh_token?: string;
expires_in?: number;
created_at?: number;
},
);
}View on GitHub (pinned to 9690622007)
Solutions
- Re-run the GitLab Duo Workflow OAuth login (loginGitLabDuoWorkflow) to obtain fresh access/refresh tokens and replace the stored credentials.
- Check GitLab Profile > Applications / Active Sessions and re-authorize if the application or token was revoked.
- Verify the stored credentials object actually contains a non-empty refresh token; re-login if it is empty or malformed.
- If the status is 5xx, retry after a short delay — it may be a transient GitLab outage.
- As a fallback, authenticate via a GitLab Personal Access Token (GITLAB_TOKEN) if the provider supports it.
Example fix
// before: assuming the stored refresh token is forever valid
await refreshGitLabDuoWorkflowToken(credentials);
// after: catch the OAuthError and fall back to interactive re-login
try {
credentials = await refreshGitLabDuoWorkflowToken(credentials);
} catch (err) {
if (err.kind === "token-refresh" && err.status === 401) {
credentials = await loginGitLabDuoWorkflow(callbacks); // re-authenticate
} else {
throw err;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!credentials?.refresh || typeof credentials.refresh !== "string") {
throw new Error("cannot refresh: missing refresh token; re-run loginGitLabDuoWorkflow");
} Type guard
function hasRefreshToken(c: unknown): c is { refresh: string } {
return typeof c === "object" && c !== null && typeof (c as { refresh?: unknown }).refresh === "string" && (c as { refresh: string }).refresh.length > 0;
} Try / catch
try {
credentials = await refreshGitLabDuoWorkflowToken(credentials);
} catch (err) {
const status = err?.status;
if (status === 401 || status === 400) {
credentials = await loginGitLabDuoWorkflow(callbacks); // token dead, re-auth
} else if (status >= 500) {
await Bun.sleep(2000); // transient GitLab outage, retry once
credentials = await refreshGitLabDuoWorkflowToken(credentials);
} else {
throw err;
}
} Prevention
- Persist refresh tokens durably and re-run login proactively when refresh fails with 400/401.
- Never hand-edit or truncate stored credential files.
- Watch GitLab status/incidents before blaming stored tokens on 5xx refresh failures.
- Fall back to GITLAB_TOKEN (PAT) where OAuth re-login is impractical.
When it happens
Trigger: The refresh request to /oauth/token returns !response.ok: expired or revoked refresh_token, token revoked by a GitLab password change or account session revocation, malformed credentials.refresh (empty/missing), or GitLab returning 4xx/5xx (invalid_client, invalid_grant, server errors).
Common situations: Long-lived sessions where the refresh token expired (GitLab refresh tokens can expire after inactivity); user revoked the app in GitLab Profile > Applications; admin disabled Duo Workflow; stored credentials were truncated by a config tool; transient GitLab 5xx outages during automatic token refresh.
Related errors
- GitLab OAuth refresh failed: ${response.status} ${await resp
- GitLab OAuth token exchange failed: ${response.status} ${awa
- OAuth refresh did not produce a usable credential for provid
- OAuth provider "${provider}" does not support token refresh
- Antigravity credentials missing projectId
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8574368cdd4ee692.
Report an issue: GitHub.