{"record":{"id":"178095a936bf7784","repo":"serverless/serverless","slug":"iam-create-role-failed","errorCode":"IAM_CREATE_ROLE_FAILED","errorMessage":"Failed to create role ${roleName}","messagePattern":"Failed to create role (.+?)","errorType":"exception","errorClass":"ServerlessError","httpStatus":null,"severity":"error","filePath":"packages/engine/src/lib/aws/iam.js","lineNumber":141,"sourceCode":"      new CreateRoleCommand({\n        RoleName: roleName,\n        AssumeRolePolicyDocument: JSON.stringify({\n          Version: '2012-10-17',\n          Statement: [\n            {\n              Effect: 'Allow',\n              Principal: {\n                Service: 'events.amazonaws.com',\n              },\n              Action: 'sts:AssumeRole',\n            },\n          ],\n        }),\n      }),\n    )\n\n    if (!createRoleResponse.Role?.Arn) {\n      throw new ServerlessError(\n        `Failed to create role ${roleName}`,\n        'IAM_CREATE_ROLE_FAILED',\n        {\n          stack: false,\n        },\n      )\n    }\n\n    const putRolePolicyResponse = await this.client.send(\n      new PutRolePolicyCommand({\n        RoleName: roleName,\n        PolicyName: 'EventBridgeApiTargetPolicy',\n        PolicyDocument: JSON.stringify({\n          Version: '2012-10-17',\n          Statement: [\n            {\n              Effect: 'Allow',\n              Action: ['events:InvokeApiDestination'],","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/serverless/serverless/blob/b9d7ea51c8cce57cff1207964b9b71123673081f/packages/engine/src/lib/aws/iam.js#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"SDK upgrade changing the CreateRoleResponse shape; corporate MITM proxy; rare AWS regional incident. Often misread as 'role creation failed' — actual creation errors throw.","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."],"exampleFix":"// before\nthrow new ServerlessError(`Failed to create role ${roleName}`, 'IAM_CREATE_ROLE_FAILED', { stack: false })\n\n// after\nthrow new ServerlessError(\n  `CreateRole '${roleName}' returned no ARN (status=${createRoleResponse.$metadata?.httpStatusCode})`,\n  'IAM_CREATE_ROLE_FAILED',\n)","handlingStrategy":"validation","validationCode":"// Validate the assume-role policy document before CreateRole\nfunction assertAssumeRolePolicy(doc) {\n  if (!doc?.Version) throw new Error('AssumeRolePolicyDocument.Version required')\n  const stmt = doc.Statement?.[0]\n  if (!stmt || stmt.Principal?.Service !== 'events.amazonaws.com' || stmt.Action !== 'sts:AssumeRole') {\n    throw new Error('Statement[0] must allow events.amazonaws.com to sts:AssumeRole')\n  }\n}","typeGuard":"function hasRoleArn(res) {\n  return Boolean(res?.Role?.Arn)\n}","tryCatchPattern":"try {\n  return await iam.createRoleForEventBridgeAPITarget(name)\n} catch (e) {\n  if (e.code === 'IAM_CREATE_ROLE_FAILED') {\n    throw new Error(`CreateRole returned no ARN; validate AssumeRolePolicyDocument. RequestId=${e.requestId}`)\n  }\n  throw e\n}","preventionTips":["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."],"tags":["iam","aws","sdk","roles"],"backgroundTag":null,"analyzedSha":"b9d7ea51c8cce57cff1207964b9b71123673081f","analyzedAt":"2026-08-13T04:14:40.386Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}