serverless/serverless · error · ServerlessError
IAM_CREATE_ROLE_FAILED
IAM_CREATE_ROLE_FAILED
Error message
Failed to create role ${roleName} What it means
Thrown by IAM at iam.js:141 when CreateRole resolves without Role.Arn. The role is created for the events.amazonaws.com service principal with an sts:AssumeRole trust policy. A missing ARN on a resolved response is an SDK contract violation — real CreateRole failures (invalid AssumeRolePolicyDocument, name conflict, path issues) throw as AWS errors before this branch. Note: the { stack: false } option is accepted but ignored by ServerlessError's constructor.
Source
Thrown at packages/engine/src/lib/aws/iam.js:141
new CreateRoleCommand({
RoleName: roleName,
AssumeRolePolicyDocument: JSON.stringify({
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Principal: {
Service: 'events.amazonaws.com',
},
Action: 'sts:AssumeRole',
},
],
}),
}),
)
if (!createRoleResponse.Role?.Arn) {
throw new ServerlessError(
`Failed to create role ${roleName}`,
'IAM_CREATE_ROLE_FAILED',
{
stack: false,
},
)
}
const putRolePolicyResponse = await this.client.send(
new PutRolePolicyCommand({
RoleName: roleName,
PolicyName: 'EventBridgeApiTargetPolicy',
PolicyDocument: JSON.stringify({
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['events:InvokeApiDestination'],View on GitHub (pinned to b9d7ea51c8)
Solutions
- Validate the AssumeRolePolicyDocument JSON (Version + Statement[].Principal.Service = 'events.amazonaws.com') before the call.
- Pin @aws-sdk/client-iam consistently across the engine.
- Log createRoleResponse.$metadata.httpStatusCode to confirm a 200 with empty body.
- Retry once for transient malformed responses.
Example fix
// before
throw new ServerlessError(`Failed to create role ${roleName}`, 'IAM_CREATE_ROLE_FAILED', { stack: false })
// after
throw new ServerlessError(
`CreateRole '${roleName}' returned no ARN (status=${createRoleResponse.$metadata?.httpStatusCode})`,
'IAM_CREATE_ROLE_FAILED',
) Defensive patterns
Strategy: validation
Validate before calling
// Validate the assume-role policy document before CreateRole
function assertAssumeRolePolicy(doc) {
if (!doc?.Version) throw new Error('AssumeRolePolicyDocument.Version required')
const stmt = doc.Statement?.[0]
if (!stmt || stmt.Principal?.Service !== 'events.amazonaws.com' || stmt.Action !== 'sts:AssumeRole') {
throw new Error('Statement[0] must allow events.amazonaws.com to sts:AssumeRole')
}
} Type guard
function hasRoleArn(res) {
return Boolean(res?.Role?.Arn)
} Try / catch
try {
return await iam.createRoleForEventBridgeAPITarget(name)
} catch (e) {
if (e.code === 'IAM_CREATE_ROLE_FAILED') {
throw new Error(`CreateRole returned no ARN; validate AssumeRolePolicyDocument. RequestId=${e.requestId}`)
}
throw e
} Prevention
- Validate the AssumeRolePolicyDocument JSON (Version + Statement.Principal.Service + Action) before CreateRole.
- Pin @aws-sdk/client-iam consistently.
- Log createRoleResponse.$metadata.requestId when the ARN is missing.
When it happens
Trigger: createRoleResponse.Role is undefined or Role.Arn is missing on a resolved promise. Causes: @aws-sdk/client-iam output-shape change, proxy stripping the body, AWS-side regression. Malformed AssumeRolePolicyDocument JSON normally throws MalformedPolicyDocumentException first.
Common situations: SDK upgrade changing the CreateRoleResponse shape; corporate MITM proxy; rare AWS regional incident. Often misread as 'role creation failed' — actual creation errors throw.
Related errors
- AWS_ECS_FAILED_TO_REGISTER_TASK_ARN
- AWS_ECS_FAILED_TO_CREATE_FARGATE_SERVICE
- EVENTBRIDGE_CREATE_CONNECTION_FAILED
- EVENTBRIDGE_CREATE_API_DESTINATION_FAILED
- EVENTBRIDGE_CREATE_RULE_FAILED
AI-assisted analysis of serverless/serverless@b9d7ea51c8 (2026-08-13).
Data as JSON: /api/errors/178095a936bf7784.
Report an issue: GitHub.