can1357/oh-my-pi · error · AIError.DevinApiError
Devin auth error ${response.status} ${response.statusText}:
Error message
Devin auth error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)} What it means
Thrown by fetchDevinAuthMetadata when the GetUserJwt HTTP call returns a non-2xx status. The response body bytes are decoded as text and embedded in the message so the caller can see the server's reason. It is a DevinApiError carrying the HTTP status code for upstream classification (e.g. auth retry logic).
Source
Thrown at packages/ai/src/providers/devin.ts:505
apiKey: string | undefined,
baseUrl: string,
fetchImpl: NonNullable<StreamOptions["fetch"]>,
signal: AbortSignal | undefined,
): Promise<{ userJwt: string; baseUrl?: string }> {
const request = create(GetUserJwtRequestSchema, { metadata: create(MetadataSchema, devinCliMetadata(apiKey)) });
const response = await fetchImpl(`${baseUrl}${DEVIN_AUTH_PATH}`, {
method: "POST",
headers: {
"content-type": "application/proto",
"connect-protocol-version": "1",
accept: "*/*",
},
body: toBinary(GetUserJwtRequestSchema, request),
signal,
});
const payload = new Uint8Array(await response.arrayBuffer());
if (!response.ok) {
throw new AIError.DevinApiError(
`Devin auth error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)}`,
response.status,
);
}
const decoded = decodeDevinUnaryMessage(GetUserJwtResponseSchema, payload);
if (!decoded?.userJwt) {
throw new AIError.ProviderResponseError("Devin auth error: GetUserJwt returned an empty user JWT", {
provider: "devin",
kind: "runtime",
});
}
const customBaseUrl = decoded.customApiServerUrl.trim();
return { userJwt: decoded.userJwt, ...(customBaseUrl ? { baseUrl: customBaseUrl.replace(/\/+$/, "") } : undefined) };
}
/**
* Resolve a server-side router (`adaptive`) into the concrete model uid plus the
* assignment JWT that authorizes it. The router uid is never a legalView on GitHub (pinned to 9690622007)
Solutions
- Check that the Devin API key is valid and not revoked/expired; re-provision it
- Verify the Devin base URL matches your instance (self-hosted vs SaaS)
- Call GetUserJwt manually (curl) to read the embedded response body message
- If 5xx, retry later or check Devin service status
Example fix
// before process.env.DEVIN_API_KEY = "stale-key" // after process.env.DEVIN_API_KEY = "<freshly-rotated devin api key>"
Defensive patterns
Strategy: try-catch
Validate before calling
// Preflight: verify the credential works before the real call
const res = await fetch(`${devinBaseUrl}/auth`, { headers: { authorization: `Bearer ${apiKey}` } });
if (!res.ok) throw new Error(`Devin credential rejected: ${res.status} — rotate the API key`); Type guard
function isDevinApiError(err: unknown): err is InstanceType<typeof AIError.DevinApiError> {
return err instanceof AIError.DevinApiError && typeof err.status === "number";
} Try / catch
try {
const meta = await fetchDevinAuthMetadata(baseUrl, request, signal);
} catch (err) {
if (err instanceof AIError.DevinApiError && (err.status === 401 || err.status === 403)) {
// refresh/rotate the Devin API key, then retry once
} else throw err;
} Prevention
- Rotate Devin API keys on a schedule and store them in a secret manager, not hard-coded
- Validate the key at startup with a cheap authenticated call
- Keep the Devin base URL in one config location to avoid instance mismatch
- Subscribe to Devin service status for outage awareness
When it happens
Trigger: POST to Devin's GetUserJwt endpoint responds 401/403/404/500 etc., with the raw body included — typically invalid or revoked Devin API key, wrong base URL, or server-side outage.
Common situations: Expired or rotated Devin credentials still configured in the environment; Devin instance URL misconfigured; Devin service outage or version change altering the auth route.
Related errors
- Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}
- Devin auth error: GetUserJwt returned an empty user JWT
- Devin AssignModel error ${response.status} ${response.status
- GitLab Duo Workflow direct_access failed with HTTP ${respons
- Qwen token/API key is required
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a50e58f0e22d0025.
Report an issue: GitHub.