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

  1. Read the status/body in the message: 401 -> run `aws sso login` again; 403 -> fix sso_account_id/sso_role_name or regain access
  2. Verify sso_account_id and sso_role_name in ~/.aws/config match an account/role you can access in the Identity Center portal
  3. Confirm sso_region (or the sso-session block's region) matches the portal's region
  4. Re-authenticate with `aws sso login --profile <profile>` to refresh the bearer token, then retry
  5. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/1cc2c012e1369392. Report an issue: GitHub.