Skip to content

fix(cfn-lang-ext): preserve template-time intrinsics with unresolved param Refs in PARTIAL mode (#9004)#9010

Merged
bnusunny merged 9 commits into
developfrom
fix/9004-language-extensions-partial-mode
May 14, 2026
Merged

fix(cfn-lang-ext): preserve template-time intrinsics with unresolved param Refs in PARTIAL mode (#9004)#9010
bnusunny merged 9 commits into
developfrom
fix/9004-language-extensions-partial-mode

Conversation

@bnusunny
Copy link
Copy Markdown
Contributor

@bnusunny bnusunny commented May 14, 2026

Which issue(s) does this change fix?

#9004

Why is this change necessary?

SAM CLI 1.160.0 introduced the in-tree CloudFormation Language Extensions resolver. Four template-time intrinsic resolvers (Fn::FindInMap, Fn::Join, Fn::Select, Fn::Base64) raise InvalidTemplateException("... layout is incorrect") when an argument resolves to an unresolved {"Ref": <param>} dict.

This breaks sam build for any template using AWS::LanguageExtensions with !Ref to a parameter that has no Default and no override — a regression from 1.159.1.

The user-reported repro:

Transform: AWS::LanguageExtensions
Parameters:
  Stage:
    Type: String  # no Default
Mappings:
  EnvConfig:
    dev: { BucketName: dev-bucket }
Resources:
  MyBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !FindInMap [EnvConfig, !Ref Stage, BucketName]

sam buildError: Fn::FindInMap layout is incorrect.

How does it address the issue?

In ResolutionMode.PARTIAL (the mode sam build always uses), preserve the call when an argument resolved to {"Ref": <name>} and <name> is a declared template parameter or a pseudo-parameter — exactly the references CloudFormation will resolve at deploy time. Resource refs and other intrinsics (Fn::GetAtt, etc.) continue to raise: those genuinely can't be inputs to template-time intrinsics at any stage, matching Kotlin compatibility behavior tested under tests/unit/lib/cfn_language_extensions/compatibility/test_kotlin_compatibility.py.

The shared discriminator is_unresolved_param_or_pseudo_ref(value, context) lives in samcli/lib/cfn_language_extensions/utils.py and is consumed by all four fixed resolvers.

Files changed:

  • samcli/lib/cfn_language_extensions/resolvers/fn_find_in_map.py — preserve when any of map_name / top_key / second_key is an unresolved param Ref (root cause of Bug: sam build fails with "Fn::FindInMap layout is incorrect" when using AWS::LanguageExtensions with an unresolved !Ref parameter as a map key (regression in 1.160.0) #9004)
  • samcli/lib/cfn_language_extensions/resolvers/fn_join.py — preserve when delimiter or list is an unresolved param Ref; widened resolve() return type to Any
  • samcli/lib/cfn_language_extensions/resolvers/fn_select.py — preserve when index is an unresolved param Ref (source-list path was already correct)
  • samcli/lib/cfn_language_extensions/resolvers/fn_base64.py — preserve when arg is an unresolved param Ref; widened resolve() return type to Any
  • samcli/lib/cfn_language_extensions/utils.py — new shared helper is_unresolved_param_or_pseudo_ref

What side effects does this change have?

None expected.

  • All Kotlin compatibility tests remain green: resource Refs and Fn::GetAtt as inputs to these template-time intrinsics still raise InvalidTemplateException (fnFindInMapWithUnsupportedFunctionFnRef, fnFindInMapWithUnsupportedFunctionFnGetAtt, fnFindInMapWithUnsupportedFunctionInMapName).
  • FULL resolution mode behavior is unchanged.
  • No public API changes; no new dependencies.
  • Test coverage: per-resolver PARTIAL-mode unit tests including positive (preserve unresolved param Ref) and regression-guard cases (FULL mode raises, resource Ref raises, Fn::GetAtt raises); end-to-end test driving process_template with the issue Bug: sam build fails with "Fn::FindInMap layout is incorrect" when using AWS::LanguageExtensions with an unresolved !Ref parameter as a map key (regression in 1.160.0) #9004 repro template; focused unit tests for the new shared helper. 1685 unit tests pass in tests/unit/lib/cfn_language_extensions/.

Mandatory Checklist

  • Review the generative AI contribution guidelines
  • Add input/output type hints to new functions/methods
  • Write design document if needed (Do I need to write a design document?) — N/A, regression fix in existing subsystem
  • Write/update unit tests
  • Write/update integration tests — N/A, behavior is fully exercised at the unit/end-to-end level via process_template
  • Write/update functional tests if needed — N/A
  • make pr passes (make lint clean for changed files; only pre-existing unrelated mypy errors remain on develop)
  • make update-reproducible-reqs if dependencies were changed — N/A, no dependency changes
  • Write documentation — N/A, no user-facing surface changes

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@bnusunny bnusunny requested a review from a team as a code owner May 14, 2026 19:33
@bnusunny bnusunny changed the title fix: preserve template-time intrinsics with unresolved param Refs in PARTIAL mode (#9004) fix(cfn-lang-ext): preserve template-time intrinsics with unresolved param Refs in PARTIAL mode (#9004) May 14, 2026
@bnusunny bnusunny requested a review from roger-zhangg May 14, 2026 20:05
bnusunny added 9 commits May 14, 2026 20:13
Hoist the helper duplicated in four resolvers (fn_find_in_map, fn_join,
fn_select, fn_base64) up to samcli/lib/cfn_language_extensions/utils.py
next to PSEUDO_PARAMETERS. Each resolver now imports the shared helper
and drops its private copy.

Adds focused unit tests in test_utils.py covering parameter Refs,
pseudo-parameter Refs, resource Refs, Fn::GetAtt, multi-key dicts,
non-string Ref targets, and contexts without a parsed_template.
@bnusunny bnusunny force-pushed the fix/9004-language-extensions-partial-mode branch from 9829353 to e475c99 Compare May 14, 2026 20:14
@bnusunny bnusunny requested a review from reedham-aws May 14, 2026 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants