can1357/oh-my-pi · error · AIError.AwsCredentialsError
sso-role
sso-role
Error message
AWS SSO GetRoleCredentials failed: ${response.status} ${body.slice(0, 200)} What it means
Thrown when the AWS SSO portal federation API (GET /federation/credentials) returns a non-OK HTTP status while fetching role credentials with a cached bearer token. The message includes the HTTP status and up to 200 chars of the response body, which usually contains the AWS error code and message explaining why the request was rejected.
Source
Thrown at packages/ai/src/providers/aws-credentials.ts:460
if (Number.isFinite(expiresAt) && expiresAt <= Date.now()) {
throw new AIError.AwsCredentialsError(
`AWS SSO token for ${startUrl} has expired. Run 'aws sso login' to refresh.`,
"sso-token-expired",
);
}
const url =
`https://portal.sso.${ssoRegion}.amazonaws.com/federation/credentials` +
`?account_id=${encodeURIComponent(profileCfg.sso_account_id)}` +
`&role_name=${encodeURIComponent(profileCfg.sso_role_name)}`;
const response = await fetchImpl(url, {
method: "GET",
headers: { "x-amz-sso_bearer_token": token.accessToken },
signal,
});
if (!response.ok) {
const body = await response.text().catch(() => "");
throw new AIError.AwsCredentialsError(
`AWS SSO GetRoleCredentials failed: ${response.status} ${body.slice(0, 200)}`,
"sso-role",
);
}
const json = (await response.json()) as {
roleCredentials?: { accessKeyId: string; secretAccessKey: string; sessionToken: string; expiration: number };
};
const role = json.roleCredentials;
if (!role)
throw new AIError.AwsCredentialsError(
"AWS SSO GetRoleCredentials: missing roleCredentials in response",
"sso-role",
);
// region is honored at the caller; we only consume defaultRegion to keep the
// param wired for symmetry with other resolution paths.
void defaultRegion;
View on GitHub (pinned to 9690622007)
Solutions
- Read the status/body in the message: 401 -> run `aws sso login` again; 403 -> fix sso_account_id/sso_role_name or regain access
- Verify sso_account_id and sso_role_name in ~/.aws/config match an account/role you can access in the Identity Center portal
- Confirm sso_region (or the sso-session block's region) matches the portal's region
- Re-authenticate with `aws sso login --profile <profile>` to refresh the bearer token, then retry
- Test the same profile with `aws sso get-role-credentials` or the AWS CLI to confirm it's account-level access
Example fix
// before (~/.aws/config) [profile corp] sso_account_id = 111122223333 sso_role_name = OldRoleName # renamed in Identity Center // after [profile corp] sso_account_id = 111122223333 sso_role_name = CurrentRoleName
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate profile SSO fields exist and look sane before the API call:
const cfg = ini[`profile ${name}`];
if (!cfg?.sso_account_id || !/^\d{12}$/.test(cfg.sso_account_id))
throw new Error(`Profile ${name}: sso_account_id missing or not a 12-digit account ID`);
if (!cfg?.sso_role_name) throw new Error(`Profile ${name}: sso_role_name missing`);
if (!cfg?.sso_region) throw new Error(`Profile ${name}: sso_region missing`); Type guard
function isSsoRoleError(err: unknown): err is Error {
return err instanceof Error && (err as { code?: string }).code === "sso-role" && /GetRoleCredentials failed/.test(err.message);
} Try / catch
try {
creds = await resolveProfileChain(profile);
} catch (err) {
if (isSsoRoleError(err)) {
if (/^AWS SSO GetRoleCredentials failed: 401/.test(err.message)) {
// token rejected server-side -> re-login
await $`aws sso login --profile ${profile}`;
} else {
// 403 etc: surface account/role access problem to the user
logger.error("SSO role fetch rejected", { detail: err.message });
}
}
throw err;
} Prevention
- Re-login when Identity Center sessions are revoked admin-side; don't rely on local expiry alone
- Keep sso_account_id/sso_role_name in sync with the Identity Center portal
- Use the sso-session form in ~/.aws/config so the CLI manages token refresh consistently
- Match sso_region to your portal's region exactly
When it happens
Trigger: readSsoCredentials() calls https://portal.sso.<sso_region>.amazonaws.com/federation/credentials with the cached access token, and response.ok is false. Causes: 401 Unauthorized (token revoked server-side despite unexpired local expiresAt), wrong sso_account_id or sso_role_name (Forbidden), sso_region mismatch, or user no longer having access to the account/role in Identity Center.
Common situations: SSO session revoked by admin or user logged out elsewhere while local cache still looks valid; profile's sso_account_id/sso_role_name edited or renamed in Identity Center; user's permission set changed removing role access; wrong sso_region configured for the portal.
Related errors
- assume-role
- sso-token-missing
- sso-token-expired
- V2 remote compaction failed (${response.status} ${response.s
- Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1cc2c012e1369392.
Report an issue: GitHub.