outline/outline · error · Error
Error while exchanging oauth code from Linear; status: ${res
Error message
Error while exchanging oauth code from Linear; status: ${res.status} What it means
Thrown by Linear OAuth code exchange when POSTing the authorization code to Linear's token endpoint returns non-200. Uses env.LINEAR_CLIENT_ID and env.LINEAR_CLIENT_SECRET (non-null asserted with !). The error includes only the status, not the response body.
Source
Thrown at plugins/linear/server/linear.ts:59
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json",
};
const body = new URLSearchParams();
body.set("code", code);
body.set("client_id", env.LINEAR_CLIENT_ID!);
body.set("client_secret", env.LINEAR_CLIENT_SECRET!);
body.set("redirect_uri", LinearUtils.callbackUrl());
body.set("grant_type", "authorization_code");
const res = await fetch(LinearUtils.tokenUrl, {
method: "POST",
headers,
body,
});
if (res.status !== 200) {
throw new Error(
`Error while exchanging oauth code from Linear; status: ${res.status}`
);
}
return AccessTokenResponseSchema.parse(await res.json());
}
static async refreshToken(refreshToken: string) {
const headers = {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json",
};
const body = new URLSearchParams();
body.set("refresh_token", refreshToken);
body.set("client_id", env.LINEAR_CLIENT_ID!);
body.set("client_secret", env.LINEAR_CLIENT_SECRET!);
body.set("grant_type", "refresh_token");View on GitHub (pinned to 935a44d4c0)
Solutions
- Confirm LINEAR_CLIENT_ID and LINEAR_CLIENT_SECRET are set and correct in server env
- Re-run the OAuth flow to obtain a fresh authorization code
- Verify LinearUtils.callbackUrl() matches the redirect URI in the Linear OAuth app
- Log the response body to get Linear's specific error reason
Example fix
// before
body.set('client_id', env.LINEAR_CLIENT_ID!);
if (res.status !== 200) {
throw new Error(`Error while exchanging oauth code from Linear; status: ${res.status}`);
}
// after - fail fast on missing creds and include body
if (!env.LINEAR_CLIENT_ID || !env.LINEAR_CLIENT_SECRET) {
throw new Error('Linear OAuth credentials are not configured');
}
body.set('client_id', env.LINEAR_CLIENT_ID);
if (res.status !== 200) {
throw new Error(`Linear OAuth exchange failed (${res.status}): ${await res.text()}`);
} Defensive patterns
Strategy: validation
Validate before calling
if (!env.LINEAR_CLIENT_ID || !env.LINEAR_CLIENT_SECRET) {
throw new Error('LINEAR_CLIENT_ID and LINEAR_CLIENT_SECRET must be configured');
} Type guard
const hasLinearCreds = (): boolean => Boolean(env.LINEAR_CLIENT_ID) && Boolean(env.LINEAR_CLIENT_SECRET);
Try / catch
try {
await Linear.exchangeCode(code);
} catch (e) {
if (e.message.startsWith('Error while exchanging oauth code from Linear')) notify('Linear connection failed - retry');
else throw e;
} Prevention
- Fail fast if LINEAR_CLIENT_ID/SECRET are unset instead of relying on ! assertions
- Match redirect_uri exactly with the Linear OAuth app
- Use the authorization code immediately after consent
When it happens
Trigger: Expired/reused authorization code; redirect_uri mismatch; LINEAR_CLIENT_ID or LINEAR_CLIENT_SECRET unset or wrong; network blocking api.linear.app; Linear OAuth app revoked or suspended.
Common situations: LINEAR_CLIENT_ID/SECRET not configured in env (the ! assertion hides undefined at runtime); redirect URI changed; slow user on consent; integration app deleted from Linear.
Related errors
- Error exchanging Figma OAuth code; status: ${res.status}, ${
- Error while validating oauth code from GitLab; status: ${res
- Error while refreshing access token from Linear; status: ${r
- Error while refreshing access token from Figma; status: ${re
- Error getting Figma current account; status: ${res.status},
AI-assisted analysis of outline/outline@935a44d4c0 (2026-08-12).
Data as JSON: /api/errors/8d739b71bf2543b2.
Report an issue: GitHub.