can1357/oh-my-pi · error · AIError.AwsCredentialsError
assume-role
assume-role
Error message
AWS AssumeRole failed: ${response.status} ${xmlTag(xml, "Message") ?? xml.slice(0, 200)} What it means
This error is thrown when an AWS STS AssumeRole API call made while resolving a profile's role_arn returns a non-OK HTTP status. The library SigV4-signs the request with the base (source) credentials and posts it to the regional STS endpoint; STS rejected the exchange, so no temporary role credentials can be returned. The message embeds the HTTP status and the STS error Message extracted from the XML response body (or the first 200 chars of raw XML).
Source
Thrown at packages/ai/src/providers/aws-credentials.ts:397
const signed = await signRequest({
method: "POST",
host: endpoint.host,
path: endpoint.pathname,
body: payload,
region,
service: "sts",
credentials: base,
headers: { "content-type": contentType },
});
const response = await fetchImpl(endpoint, {
method: "POST",
headers: { ...signed, "content-type": contentType },
body: payload,
signal,
});
const xml = await response.text();
if (!response.ok) {
throw new AIError.AwsCredentialsError(
`AWS AssumeRole failed: ${response.status} ${xmlTag(xml, "Message") ?? xml.slice(0, 200)}`,
"assume-role",
);
}
return parseStsCredentials(xml, "AWS AssumeRole", "assume-role");
}
interface SsoCachedToken {
accessToken?: string;
expiresAt?: string;
startUrl?: string;
region?: string;
}
async function readSsoCredentials(
profileCfg: Record<string, string>,
configIni: AwsIniFile | undefined,
defaultRegion: string,View on GitHub (pinned to 9690622007)
Solutions
- Read the embedded STS Message in the error: AccessDenied -> fix IAM/trust policy, ExternalId -> align profile external_id with trust policy, ExpiredToken -> refresh base credentials
- Verify role_arn, external_id, duration_seconds, and source_profile/credential_source in ~/.aws/config
- Confirm the base credentials are valid: aws sts get-caller-identity with those credentials
- Confirm the IAM identity has sts:AssumeRole allowed on the target role and the role's trust policy allows the source principal
- Test the same chain with `aws sts assume-role --role-arn ...` to confirm it's a config issue, not library-specific
Example fix
// before (~/.aws/config) [profile deploy] role_arn = arn:aws:iam::123456789012:role/Deploy source_profile = base duration_seconds = 72000 // invalid: max 43200 // after [profile deploy] role_arn = arn:aws:iam::123456789012:role/Deploy source_profile = base duration_seconds = 3600
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check base credentials are live before assuming the role:
import { $ } from "bun";
const r = await $`aws sts get-caller-identity`.quiet().nothrow();
if (r.exitCode !== 0) throw new Error("Base AWS credentials invalid; fix source_profile/keys before AssumeRole"); Type guard
function isAssumeRoleError(err: unknown): err is Error & { code: string } {
return err instanceof Error && "code" in err && (err as { code?: string }).code === "assume-role";
} Try / catch
try {
creds = await resolveProfileChain(profile);
} catch (err) {
if (isAssumeRoleError(err)) {
// message embeds HTTP status + STS Message; surface to user with profile name
logger.error("STS AssumeRole rejected", { profile, detail: err.message });
}
throw err;
} Prevention
- Always test the profile chain with `aws sts assume-role` / the AWS CLI before wiring it into automation
- Keep source_profile credentials fresh and ensure IAM allows sts:AssumeRole on the target role
- Match external_id in the profile to the role trust policy exactly
- Keep duration_seconds within 900-43200 and at or below the role's MaxSessionDuration
- Use the correct region so the regional STS endpoint is enabled for the account
When it happens
Trigger: stsAssumeRole() receives response.ok === false from the STS endpoint. Typical causes: base credentials lack sts:AssumeRole permission on the target role (AccessDenied), wrong role_arn, invalid/mismatched external_id, duration_seconds outside 900-43200, expired or untrusted source credentials (ExpiredToken/InvalidClientTokenId), or wrong region for the STS endpoint.
Common situations: Cross-account role assumption where the trust policy's ExternalId doesn't match the profile's external_id; IAM policy missing sts:AssumeRole on the role ARN; typos in role_arn in ~/.aws/config; using a region whose STS endpoint the account hasn't enabled; stale long-lived keys rotated or revoked; role trust policy not listing the source principal.
Related errors
- sso-role
- sso-token-missing
- sso-token-expired
- ${source} response is missing credentials.
- ssh reverse forward to ${config.sshTarget} exited with code
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/dcaaa64a0721541c.
Report an issue: GitHub.