Skip to content

fix(lambda): publish stable alias for durable functions#13589

Merged
czubocha merged 2 commits into
mainfrom
claude/friendly-leakey-01b4d9
May 27, 2026
Merged

fix(lambda): publish stable alias for durable functions#13589
czubocha merged 2 commits into
mainfrom
claude/friendly-leakey-01b4d9

Conversation

@czubocha
Copy link
Copy Markdown
Contributor

@czubocha czubocha commented May 18, 2026

Summary

Fixes durable Lambda functions failing to be invoked through any event source the framework wires with an unqualified ARN (Fn::GetAtt: [Function, Arn]). AWS rejects unqualified invocations of durable functions with:

InvalidParameterValueException: You cannot invoke a durable function using an unqualified ARN.

Affected event sources include scheduled events (both method: scheduler and method: eventBus), SNS, API Gateway, and every other source that relies on the framework's standard target wiring.

Why an alias and not $LATEST

A blanket $LATEST qualifier is not viable: AWS rejects $LATEST on AWS::Lambda::Permission ("We currently do not support adding policies for $LATEST"), which is required by most non-scheduler event sources. The only qualifier that works uniformly across Rule.Target.Arn, Subscription.Endpoint, Lambda::Permission.FunctionName, EventInvokeConfig.Qualifier, etc. is a real alias or numeric version. An alias is the stable choice — same rationale used for snapStart and provisionedConcurrency aliases.

Changes

  • packages/serverless/lib/plugins/aws/package/compile/functions.js — when functionObject.durableConfig is set and functionObject.targetAlias is not already set by snapStart/provisionedConcurrency, auto-create an AWS::Lambda::Alias named durable pointing at the published AWS::Lambda::Version, and populate functionObject.targetAlias. Mirrors the existing snapStart block at the same line region.
  • packages/serverless/lib/plugins/aws/package/compile/functions.js — throw FUNCTION_DURABLE_REQUIRES_VERSIONING early when durableConfig is combined with versionFunction: false, since that combination would generate broken CloudFormation referencing a non-existent Version resource.
  • packages/serverless/lib/plugins/aws/lib/naming.js — add getLambdaDurableAliasLogicalId(functionName) and getLambdaDurableEnabledAliasName() helpers, following the snapStart naming convention.
  • docs/sf/providers/aws/guide/functions.md — update the Durable Functions note to describe the alias and the versionFunction: false rejection.
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js — five new tests inside Durable Functions Support > Alias:
    1. Alias resource is created with correct properties
    2. functionObject.targetAlias is populated for downstream consumers
    3. Pre-existing targetAlias (e.g. from snapStart) wins; no double-aliasing
    4. versionFunction: true + durableConfig positive case
    5. versionFunction: false + durableConfig rejection

IAM impact

None on identity-based policies — the scheduler role's lambda:InvokeFunction already covers function:NAME:*, which matches any alias name. The AWS-managed AWSLambdaBasicDurableExecutionRolePolicy is Resource: "*" and works for any qualifier. Resource-based Lambda::Permission resources have their FunctionName change from unqualified to alias-qualified — this is the actual fix mechanism.

Test plan

  • npm test — 1710/1710 unit tests pass
  • npm run lint — clean
  • npm run prettier — clean
  • End-to-end against real AWS using a durable function with each affected event source:
    • events.schedule method: scheduler — verified invocations succeed, alias-qualified target
    • events.schedule method: eventBus — verified invocations succeed, alias-qualified Target and Permission
    • events.sns — verified SNS delivery succeeds and Lambda is invoked through the alias

Backwards compatibility

For functions without durableConfig, the generated CloudFormation is byte-identical. For existing durable users, the upgrade deploy adds one AWS::Lambda::Alias resource and changes Lambda::Permission.FunctionName to alias-qualified (a CFN resource replacement). Since durable + event sources was not working before this fix, the transition turns a broken stack into a working one without regressing any previously-working path.

Closes #13587

Summary by CodeRabbit

  • New Features

    • Added Durable Functions support for AWS Lambda: durable-configured functions now auto-enable versioning and get a stable "durable" alias; supported on Node.js 22+ and Python 3.13+ runtimes.
  • Bug Fixes / Validation

    • Compilation now rejects pairing durable configuration with disabled versioning (explicit versionFunction: false).
  • Documentation

    • Updated provider guide with Durable Functions requirements and behavior.

Review Change Stack


Note

Medium Risk
Changes CloudFormation for durable functions (new alias, qualified permissions/targets) and affects all event-source wiring via targetAlias, though non-durable stacks are unchanged and behavior matches existing snapStart alias patterns.

Overview
Fixes durable Lambda deployments so framework-wired event sources invoke a qualified target instead of an unqualified function ARN, which AWS rejects for durable functions.

When durableConfig is set and no other feature already chose an alias (snapStart, provisioned concurrency), compile now emits an AWS::Lambda::Alias named durable on the latest published version and sets functionObject.targetAlias so schedules, SNS, API Gateway, permissions, and similar integrations follow the same alias path as other versioned features. versionFunction: false with durableConfig fails fast with FUNCTION_DURABLE_REQUIRES_VERSIONING. Naming helpers and docs describe the alias and rejection; unit tests cover alias creation, targetAlias, precedence, and the versioning guard.

Reviewed by Cursor Bugbot for commit a1414b3. Bugbot is set up for automated code reviews on this repo. Configure here.

Durable Lambda functions require qualified ARNs for invocation -
AWS rejects unqualified invocations with InvalidParameterValueException.
This affected every event source the framework wired with an unqualified
target (scheduled events, EventBridge, SNS, API Gateway, etc.) since
they all emit `Fn::GetAtt: [Function, Arn]` by default.

A `$LATEST` qualifier is not a generalizable fix because AWS rejects
`$LATEST` on `AWS::Lambda::Permission` ("We currently do not support
adding policies for $LATEST"), which most non-scheduler event sources
rely on.

Auto-create an `AWS::Lambda::Alias` named `durable` for every function
with `durableConfig`, mirroring the existing snapStart and
provisionedConcurrency alias patterns. Set `functionObject.targetAlias`
so all downstream consumers pick up the alias via the existing
`resolveLambdaTarget` plumbing - no per-event-source changes needed.

Reject the `durableConfig + versionFunction: false` combination
explicitly, since it would produce broken CFN with a dangling Version
reference.

Closes #13587
@Mmarzex
Copy link
Copy Markdown
Contributor

Mmarzex commented May 18, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

📝 Walkthrough

Walkthrough

Adds durable Lambda alias support: naming helpers, validation that disables incompatible configs, automatic creation of a stable durable AWS::Lambda::Alias when durableConfig is present, test coverage for alias behavior, and documentation updates describing runtime and configuration requirements.

Changes

Durable Lambda Alias Support

Layer / File(s) Summary
Durable Alias Naming Helpers
packages/serverless/lib/plugins/aws/lib/naming.js
Adds getLambdaDurableAliasLogicalId(functionName) and getLambdaDurableEnabledAliasName() to produce the CloudFormation logical ID and canonical alias name durable.
Durable Config Validation
packages/serverless/lib/plugins/aws/package/compile/functions.js
Adds fail-fast validation that rejects durableConfig when versionFunction is explicitly false.
Alias Resource Creation
packages/serverless/lib/plugins/aws/package/compile/functions.js
When durableConfig is present and no other alias target is set, creates an AWS::Lambda::Alias named durable, sets functionObject.targetAlias to that alias, and depends the alias on the published function version.
Durable Alias Test Coverage
packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
Mocks durable naming helpers and adds an "Alias" test suite validating CloudFormation alias generation, targetAlias propagation, non-interference with snapStart, creation with explicit versionFunction: true, and rejection when combined with versionFunction: false.
Durable Functions Documentation
docs/sf/providers/aws/guide/functions.md
Expands the Durable Functions note to document runtime limits (Node.js 22+, Python 3.13+), automatic versioning enablement, creation of the durable alias, event-source routing to that alias, and invalid configuration combinations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • eahefnawy

Poem

🐰 I hopped in code to name a friend,
A steady alias to the very end.
Tests and docs stitched in a row,
Event sources now always know —
Durable dreams run, steady and zen.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(lambda): publish stable alias for durable functions' clearly and concisely describes the primary change: creating a stable alias for durable Lambda functions to resolve invocation issues.
Linked Issues check ✅ Passed The PR fully addresses the requirement from issue #13587: it implements qualified ARN usage for durable functions by creating a stable 'durable' alias, ensuring event sources invoke durable lambdas with qualified ARNs instead of unqualified ones.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing durable function alias support: naming helpers, compilation logic, validation rules, documentation updates, and corresponding test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/friendly-leakey-01b4d9

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js (1)

449-480: ⚡ Quick win

Test name overstates provisionedConcurrency coverage.

This case validates only snapStart, but the title claims snapStart or provisionedConcurrency. Either rename it or add a dedicated provisionedConcurrency precedence test to match the stated contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js`
around lines 449 - 480, The test titled "should not overwrite a targetAlias
already set by snapStart or provisionedConcurrency" only exercises snapStart;
either rename the test to reflect snapStart-only behavior (e.g., mention
snapStart precedence) or add a separate test that sets up provisionedConcurrency
on the function and asserts the same precedence behavior; locate the test suite
using the existing it(...) block around the awsCompileFunctions.compileFunctions
invocation and the func fixture to update the test name or duplicate the block
with provisionedConcurrency configured to verify its precedence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/sf/providers/aws/guide/functions.md`:
- Line 455: Update the Durable Functions note to explicitly state the exception:
when durableConfig is enabled it normally sets versionFunctions: true and
publishes an AWS::Lambda::Alias named durable and targets that alias for
event-source integrations, but if another feature already sets a target alias
(e.g., snapStart or provisionedConcurrency via targetAlias), the durable alias
creation is skipped and integrations will target the existing alias instead;
also mention that setting versionFunctions: false together with durableConfig
remains rejected.

---

Nitpick comments:
In
`@packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js`:
- Around line 449-480: The test titled "should not overwrite a targetAlias
already set by snapStart or provisionedConcurrency" only exercises snapStart;
either rename the test to reflect snapStart-only behavior (e.g., mention
snapStart precedence) or add a separate test that sets up provisionedConcurrency
on the function and asserts the same precedence behavior; locate the test suite
using the existing it(...) block around the awsCompileFunctions.compileFunctions
invocation and the func fixture to update the test name or duplicate the block
with provisionedConcurrency configured to verify its precedence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3a0ac771-a6d2-4bc8-86a9-9630a59050fc

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb17c5 and d9cad38.

📒 Files selected for processing (4)
  • docs/sf/providers/aws/guide/functions.md
  • packages/serverless/lib/plugins/aws/lib/naming.js
  • packages/serverless/lib/plugins/aws/package/compile/functions.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js

```

**Note:** Durable Functions are currently supported only for Node.js 22+ and Python 3.13+ runtimes. Enabling `durableConfig` will automatically enable function versioning (`versionFunctions: true`) as durable functions require qualified ARNs.
**Note:** Durable Functions are currently supported only for Node.js 22+ and Python 3.13+ runtimes. Enabling `durableConfig` will automatically enable function versioning (`versionFunctions: true`) and publish an `AWS::Lambda::Alias` named `durable` pointing at the latest version, because AWS rejects unqualified invocations of durable functions. All event-source integrations (schedule, EventBridge, SNS, API Gateway, etc.) target this alias so invocations succeed without further configuration. Setting `versionFunction: false` together with `durableConfig` is rejected.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify alias behavior when another feature already sets targetAlias.

The note currently implies durable is always published and always targeted. In practice, this PR skips durable alias creation when snapStart/provisionedConcurrency already set a target alias. Please document that exception explicitly.

Suggested wording tweak
-... publish an `AWS::Lambda::Alias` named `durable` ... All event-source integrations ... target this alias ...
+... publish an `AWS::Lambda::Alias` named `durable` (unless another feature such as SnapStart or provisioned concurrency already sets a target alias) ... Event-source integrations target the resolved target alias ...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/sf/providers/aws/guide/functions.md` at line 455, Update the Durable
Functions note to explicitly state the exception: when durableConfig is enabled
it normally sets versionFunctions: true and publishes an AWS::Lambda::Alias
named durable and targets that alias for event-source integrations, but if
another feature already sets a target alias (e.g., snapStart or
provisionedConcurrency via targetAlias), the durable alias creation is skipped
and integrations will target the existing alias instead; also mention that
setting versionFunctions: false together with durableConfig remains rejected.

@czubocha
Copy link
Copy Markdown
Contributor Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a1414b3. Configure here.

@czubocha czubocha merged commit 19bc9b1 into main May 27, 2026
13 checks passed
@czubocha czubocha deleted the claude/friendly-leakey-01b4d9 branch May 27, 2026 13:15
@github-actions github-actions Bot locked and limited conversation to collaborators May 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Durable lambdas not working with schedules

2 participants