{"record":{"id":"1cc2c012e1369392","repo":"can1357/oh-my-pi","slug":"sso-role","errorCode":"sso-role","errorMessage":"AWS SSO GetRoleCredentials failed: ${response.status} ${body.slice(0, 200)}","messagePattern":"AWS SSO GetRoleCredentials failed: (.+?) (.+?)","errorType":"error_code","errorClass":"AIError.AwsCredentialsError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/aws-credentials.ts","lineNumber":460,"sourceCode":"\tif (Number.isFinite(expiresAt) && expiresAt <= Date.now()) {\n\t\tthrow new AIError.AwsCredentialsError(\n\t\t\t`AWS SSO token for ${startUrl} has expired. Run 'aws sso login' to refresh.`,\n\t\t\t\"sso-token-expired\",\n\t\t);\n\t}\n\n\tconst url =\n\t\t`https://portal.sso.${ssoRegion}.amazonaws.com/federation/credentials` +\n\t\t`?account_id=${encodeURIComponent(profileCfg.sso_account_id)}` +\n\t\t`&role_name=${encodeURIComponent(profileCfg.sso_role_name)}`;\n\tconst response = await fetchImpl(url, {\n\t\tmethod: \"GET\",\n\t\theaders: { \"x-amz-sso_bearer_token\": token.accessToken },\n\t\tsignal,\n\t});\n\tif (!response.ok) {\n\t\tconst body = await response.text().catch(() => \"\");\n\t\tthrow new AIError.AwsCredentialsError(\n\t\t\t`AWS SSO GetRoleCredentials failed: ${response.status} ${body.slice(0, 200)}`,\n\t\t\t\"sso-role\",\n\t\t);\n\t}\n\tconst json = (await response.json()) as {\n\t\troleCredentials?: { accessKeyId: string; secretAccessKey: string; sessionToken: string; expiration: number };\n\t};\n\tconst role = json.roleCredentials;\n\tif (!role)\n\t\tthrow new AIError.AwsCredentialsError(\n\t\t\t\"AWS SSO GetRoleCredentials: missing roleCredentials in response\",\n\t\t\t\"sso-role\",\n\t\t);\n\n\t// region is honored at the caller; we only consume defaultRegion to keep the\n\t// param wired for symmetry with other resolution paths.\n\tvoid defaultRegion;\n","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/aws-credentials.ts#L442-L478","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (~/.aws/config)\n[profile corp]\nsso_account_id = 111122223333\nsso_role_name = OldRoleName   # renamed in Identity Center\n\n// after\n[profile corp]\nsso_account_id = 111122223333\nsso_role_name = CurrentRoleName","handlingStrategy":"try-catch","validationCode":"// Validate profile SSO fields exist and look sane before the API call:\nconst cfg = ini[`profile ${name}`];\nif (!cfg?.sso_account_id || !/^\\d{12}$/.test(cfg.sso_account_id))\n  throw new Error(`Profile ${name}: sso_account_id missing or not a 12-digit account ID`);\nif (!cfg?.sso_role_name) throw new Error(`Profile ${name}: sso_role_name missing`);\nif (!cfg?.sso_region) throw new Error(`Profile ${name}: sso_region missing`);","typeGuard":"function isSsoRoleError(err: unknown): err is Error {\n  return err instanceof Error && (err as { code?: string }).code === \"sso-role\" && /GetRoleCredentials failed/.test(err.message);\n}","tryCatchPattern":"try {\n  creds = await resolveProfileChain(profile);\n} catch (err) {\n  if (isSsoRoleError(err)) {\n    if (/^AWS SSO GetRoleCredentials failed: 401/.test(err.message)) {\n      // token rejected server-side -> re-login\n      await $`aws sso login --profile ${profile}`;\n    } else {\n      // 403 etc: surface account/role access problem to the user\n      logger.error(\"SSO role fetch rejected\", { detail: err.message });\n    }\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["aws","sso","authentication","http","network"],"backgroundTag":"aws-sso-credentials-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}