serverless/serverless · error · ServerlessError

SNS_MISSING_TOPIC_NAME

SNS_MISSING_TOPIC_NAME

Error message

Missing "sns.topicName" setting (it needs to be provided if "sns.arn" is not provided as plain ARN string)

What it means

Thrown when 'sns.arn' is provided as a CloudFormation intrinsic function (an object like { 'Fn::GetAtt': [...] }, not a plain string) and 'sns.topicName' is not provided. The framework needs the bare topic name to author the subscription resource; it can extract the name from a string ARN but cannot parse it out of an intrinsic function. The check fires at sns.js:148-154 after the string-ARN branch has run.

Source

Thrown at packages/serverless/lib/plugins/aws/package/compile/events/sns.js:150

                topicArn = event.sns.arn
                if (typeof topicArn === 'string') {
                  // NOTE: we need to process the topic ARN that way due to lacking
                  // support of regex lookbehind in Node.js 6.
                  // Once Node.js 6 support is dropped we can change this to:
                  // `const splitArn = topicArn.split(/(?<!:):(?!:)/);`
                  const splitArn = topicArn
                    .replace(/::/g, '@@')
                    .split(':')
                    .map((s) => s.replace(/@@/g, '::'))
                  topicName = splitArn[splitArn.length - 1]
                  if (splitArn[3] !== this.options.region) {
                    region = splitArn[3]
                  }
                }
                topicName = event.sns.topicName || topicName
                // Only true when providing CFN intrinsic function (not string) to arn property without topicName property
                if (!topicName) {
                  throw new ServerlessError(
                    'Missing "sns.topicName" setting (it needs to be provided if "sns.arn" is not provided as plain ARN string)',
                    'SNS_MISSING_TOPIC_NAME',
                  )
                }
              } else {
                topicName = event.sns.topicName
              }
            } else if (event.sns.indexOf('arn:') === 0) {
              topicArn = event.sns
              const splitArn = topicArn.split(':')
              topicName = splitArn[splitArn.length - 1]
            } else {
              topicName = event.sns
            }

            if (event.sns.redrivePolicy) {
              const {
                deadLetterTargetArn,

View on GitHub (pinned to b9d7ea51c8)

Solutions

  1. Add 'topicName: <name>' alongside the intrinsic 'arn'.
  2. If the topic is in this stack, use the topic's logical name via provider-style reference or supply a plain string ARN.
  3. Ensure the topicName matches the topic that the intrinsic resolves to at deploy time.

Example fix

# before
events:
  - sns:
      arn: { "Fn::GetAtt": [MyTopic, Arn] }
# after
events:
  - sns:
      arn: { "Fn::GetAtt": [MyTopic, Arn] }
      topicName: my-topic
Defensive patterns

Strategy: type-guard

Validate before calling

function validateSnsEvent(event) {
  if (!event.sns || typeof event.sns !== 'object') return
  const arn = event.sns.arn
  if (arn != null && typeof arn === 'object' && !event.sns.topicName) {
    throw new Error('sns.arn is a CloudFormation intrinsic; sns.topicName must be set explicitly')
  }
}

Type guard

function isIntrinsic(v) {
  return v != null && typeof v === 'object' &&
    (Object.keys(v).includes('Ref') || Object.keys(v).some(k => k.startsWith('Fn::')))
}
function needsTopicName(snsEvent) {
  return snsEvent && typeof snsEvent === 'object' && snsEvent.arn != null &&
    typeof snsEvent.arn === 'object' && snsEvent.topicName == null
}

Prevention

When it happens

Trigger: Configuring 'sns: { arn: { "Fn::GetAtt": [MyTopic, Arn] } }' or 'arn: { Ref: TopicArnParam }' without a sibling 'topicName'. The framework cannot derive a topic name from an intrinsic and so requires it explicitly.

Common situations: Referencing a topic exported from another stack via Cross-Stack Reference or a CloudFormation parameter; migrating from a hard-coded ARN string to a dynamic reference and forgetting to add topicName.

Related errors


AI-assisted analysis of serverless/serverless@b9d7ea51c8 (2026-08-13). Data as JSON: /api/errors/ec0ddbaacaad7631. Report an issue: GitHub.