decolua/9router · error
Failed to start device authorization: ${error}
Error message
Failed to start device authorization: ${error} What it means
Thrown by KiroService.startDeviceAuthorization when the AWS SSO OIDC device_authorization endpoint returns non-2xx. The response body (AWS error JSON) is embedded in the message. This step creates the deviceCode/userCode pair, so failure aborts the Builder ID / IDC device login before the user ever sees a verification URL.
Source
Thrown at src/lib/oauth/services/kiro.js:71
async startDeviceAuthorization(clientId, clientSecret, startUrl, region = "us-east-1") {
assertValidAwsRegion(region);
const endpoint = `https://oidc.${region}.amazonaws.com/device_authorization`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
clientId,
clientSecret,
startUrl,
}),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to start device authorization: ${error}`);
}
const data = await response.json();
return {
deviceCode: data.deviceCode,
userCode: data.userCode,
verificationUri: data.verificationUri,
verificationUriComplete: data.verificationUriComplete,
expiresIn: data.expiresIn,
interval: data.interval || 5,
};
}
/**
* Poll for token using device code (AWS Builder ID/IDC)
*/
async pollDeviceToken(clientId, clientSecret, deviceCode, region = "us-east-1") {
assertValidAwsRegion(region);View on GitHub (pinned to 90b52e06ff)
Solutions
- Call registerClient again to obtain fresh clientId/clientSecret and retry — expired client secrets are the most common cause.
- Check the error body in the message for invalid_client / invalidRequest details.
- Ensure the same region is used for registerClient and startDeviceAuthorization.
- Back off and retry if the body shows throttling.
Example fix
// before: reusing long-lived cached client creds await svc.startDeviceAuthorization(saved.clientId, saved.clientSecret, startUrl); // after: re-register when the client secret expired const client = saved.clientSecretExpiresAt > Date.now()/1000 ? saved : await svc.registerClient(region); await svc.startDeviceAuthorization(client.clientId, client.clientSecret, startUrl, region);
Defensive patterns
Strategy: retry
Validate before calling
function hasClientCreds(c) {
return typeof c?.clientId === 'string' && c.clientId.length > 0 &&
typeof c?.clientSecret === 'string' && c.clientSecret.length > 0 &&
(!c.clientSecretExpiresAt || c.clientSecretExpiresAt * 1000 > Date.now());
}
if (!hasClientCreds(saved)) throw new Error('Client credentials missing or expired — call registerClient first'); Type guard
function isDeviceAuthResult(d) { return typeof d?.deviceCode === 'string' && typeof d?.userCode === 'string' && typeof d?.verificationUri === 'string'; } Try / catch
try {
return await svc.startDeviceAuthorization(clientId, clientSecret, startUrl, region);
} catch (e) {
if (/invalid_client|expired/i.test(e.message)) {
const c = await svc.registerClient(region);
return svc.startDeviceAuthorization(c.clientId, c.clientSecret, startUrl, region);
}
throw e;
} Prevention
- Re-register the OIDC client whenever clientSecretExpiresAt has passed instead of reusing cached credentials.
- Keep registration and device-authorization in the same region.
- Persist clientId/clientSecret together as one unit to avoid partial-state bugs.
- Handle 429 with exponential backoff before surfacing the error.
When it happens
Trigger: POST to oidc.<region>.amazonaws.com/device_authorization with clientId/clientSecret/startUrl returns !response.ok — most often an invalid or expired clientId/clientSecret from a previous registerClient, or an unknown region.
Common situations: Reusing cached client credentials after their clientSecretExpiresAt passed; registerClient previously failed partially and stale credentials were persisted; region mismatch between registration and device-authorization calls; AWS 429 throttling.
Related errors
- Failed to register client: ${error}
- `CodeBuddy state request failed: ${await response.text()}`
- `CodeBuddy Intl state request failed: ${await response.text(
- Token refresh failed: ${error}
- Failed to list profiles: ${error}
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/30dff0e96ac934c4.
Report an issue: GitHub.