Skip to content

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

@polyomino24

Description

@polyomino24

Description:

sam build fails with Fn::FindInMap layout is incorrect when a template uses AWS::LanguageExtensions with Fn::FindInMap where a template parameter is used as a map key via !Ref, and no value is supplied for that parameter at build time (i.e., without --parameter-overrides and no Default defined).
This seems to be a regression introduced in 1.160.0 — the same template built successfully with 1.159.1.

Steps to reproduce:

  1. Create a new directory and add the following files:

samconfig.yaml

version: 0.1
stg:
  global:
    parameters:
      parameter_overrides:
        - ENV=stg

template.yaml

AWSTemplateFormatVersion: 2010-09-09
Transform:
  - AWS::Serverless-2016-10-31
  - AWS::LanguageExtensions

Parameters:
  ENV:
    Type: String
    AllowedValues: [stg, prod]

Resources:
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: .
      Handler: index.handler
      Runtime: nodejs22.x
      Role: !FindInMap [EnvConfig, !Ref ENV, IAM]

Mappings:
  EnvConfig:
    stg:
      IAM: arn:aws:iam::123456789012:role/lambda-role-stg
    prod:
      IAM: arn:aws:iam::123456789012:role/lambda-role-prod

index.js

export const handler = async (_event, _context) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello World',
    }),
  }
}
  1. Run sam build in that directory with AWS SAM CLI v1.160.0

Observed result:

Show output
% sam build --debug      
2026-05-14 15:42:16,844 | Config file location:                                            
/Users/ta.ishikawa/sam-cli-bug/samconfig.yaml                                              
2026-05-14 15:42:16,849 | Loading configuration values from [default.['build'].parameters] 
(env.command_name.section) in config file at                                               
'/Users/ta.ishikawa/sam-cli-bug/samconfig.yaml'...                                         
2026-05-14 15:42:16,849 | Configuration values successfully loaded.                        
2026-05-14 15:42:16,850 | Configuration values are: {}                                     
2026-05-14 15:42:16,851 | Using SAM Template at                                            
/Users/ta.ishikawa/sam-cli-bug/template.yaml                                               
2026-05-14 15:42:16,852 | Empty parameter set ({})                                         
2026-05-14 15:42:16,876 | OSError occurred while reading TOML file: [Errno 2] No such file 
or directory: '/Users/ta.ishikawa/sam-cli-bug/samconfig.toml'                              
2026-05-14 15:42:16,877 | Using config file: samconfig.toml, config environment: default   
2026-05-14 15:42:16,878 | Expand command line arguments to:                                
2026-05-14 15:42:16,878 | --template_file=/Users/ta.ishikawa/sam-cli-bug/template.yaml     
--mount_with=READ --build_dir=.aws-sam/build --cache_dir=.aws-sam/cache                    
2026-05-14 15:42:16,941 | 'build' command is called                                        
2026-05-14 15:42:16,942 | Expanding CloudFormation Language Extensions (Phase 1)           
2026-05-14 15:42:16,943 | Processing Fn::ForEach constructs in template                    
2026-05-14 15:42:16,943 | Resolving intrinsic functions in template                        
2026-05-14 15:42:16,944 | Failed to expand CloudFormation Language Extensions:             
Fn::FindInMap layout is incorrect                                                          
2026-05-14 15:42:16,944 | Telemetry endpoint configured to be                              
https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics                     
2026-05-14 15:42:17,004 | No container socket path in global storage, falling back to      
DOCKER_HOST detection:                                                                     
2026-05-14 15:42:17,005 | Telemetry endpoint configured to be                              
https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics                     
2026-05-14 15:42:17,005 | Unable to find Click Context for getting session_id.             
2026-05-14 15:42:17,006 | No container socket path in global storage, falling back to      
DOCKER_HOST detection:                                                                     
2026-05-14 15:42:17,007 | Sending Telemetry: {'metrics': [{'commandRun': {'requestId':     
'b6466981-55a4-44ed-87e5-d630d5d362cd', 'installationId':                                  
'0fe4a75f-9858-4a11-99c0-5e7442a73e66', 'sessionId':                                       
'8baa53f2-54da-4d69-8f30-5c2f7c9fa5e7', 'executionEnvironment': 'CLI', 'ci': False,        
'pyversion': '3.13.11', 'samcliVersion': '1.160.0', 'osPlatform': 'Darwin',                
'awsProfileProvided': False, 'debugFlagProvided': True, 'region': '', 'commandName': 'sam  
build', 'metricSpecificAttributes': {'projectType': 'CFN', 'gitOrigin': None,              
'projectName': 'f9fbd5b7efdc83a3be25efdc23b036d1a8f30b42b0cd3d93878fb16d5ccb80a3',         
'initialCommit': None, 'containerEngine': 'docker-default', 'adminContainerPreference':    
None}, 'duration': 66, 'exitReason': 'InvalidSamDocumentException', 'exitCode': 255}}]}    
2026-05-14 15:42:17,007 | Sending Telemetry: {'metrics': [{'events': {'requestId':         
'cb03bbbc-7750-4173-bc4b-cd575edc9164', 'installationId':                                  
'0fe4a75f-9858-4a11-99c0-5e7442a73e66', 'sessionId':                                       
'8baa53f2-54da-4d69-8f30-5c2f7c9fa5e7', 'executionEnvironment': 'CLI', 'ci': False,        
'pyversion': '3.13.11', 'samcliVersion': '1.160.0', 'osPlatform': 'Darwin', 'commandName': 
'sam build', 'metricSpecificAttributes': {'events': [{'event_name':                        
'SamConfigFileExtension', 'event_value': '.yaml', 'thread_id':                             
'7b770acae30e4e35af06873f64ecae54', 'time_stamp': '2026-05-14 06:42:16.844088+00',         
'exception_name': None}, {'event_name': 'SamConfigFileExtension', 'event_value': '.toml',  
'thread_id': '2d863e0b995e4373b77a3a70a49b2d68', 'time_stamp': '2026-05-14                 
06:42:16.877624+00', 'exception_name': None}], 'containerEngine': 'docker-default'}}}]}    
2026-05-14 15:42:17,433 |                                                                  
HTTPSConnectionPool(host='aws-serverless-tools-telemetry.us-west-2.amazonaws.com',         
port=443): Read timed out. (read timeout=0.1)                                              
2026-05-14 15:42:17,435 |                                                                  
HTTPSConnectionPool(host='aws-serverless-tools-telemetry.us-west-2.amazonaws.com',         
port=443): Read timed out. (read timeout=0.1)                                              

Error: Fn::FindInMap layout is incorrect
Traceback:
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/click/core.py", line 1082, in main
    rv = self.invoke(ctx)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/click/core.py", line 1443, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/cli/cli_config_file.py", line 366, in wrapper
    return func(*args, **kwargs)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/click/decorators.py", line 92, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/lib/telemetry/metric.py", line 190, in wrapped
    raise exception  # pylint: disable=raising-bad-type
    ^^^^^^^^^^^^^^^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/lib/telemetry/metric.py", line 155, in wrapped
    return_value = func(*args, **kwargs)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/lib/utils/version_checker.py", line 43, in wrapped
    actual_result = func(*args, **kwargs)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/cli/main.py", line 95, in wrapper
    return func(*args, **kwargs)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/commands/build/command.py", line 175, in cli
    do_cli(
    ~~~~~~^
        ctx,
        ^^^^
    ...<22 lines>...
        use_buildkit,
        ^^^^^^^^^^^^^
    )  # pragma: no cover
    ^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/commands/build/command.py", line 244, in do_cli
    with BuildContext(
         ~~~~~~~~~~~~^
        function_identifier,
        ^^^^^^^^^^^^^^^^^^^^
    ...<22 lines>...
        use_buildkit=use_buildkit,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    ) as ctx:
    ^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/commands/build/build_context.py", line 202, in __enter__
    self.set_up()
    ~~~~~~~~~~~^^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/commands/build/build_context.py", line 208, in set_up
    self._stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        self._template_file,
        ^^^^^^^^^^^^^^^^^^^^
        parameter_overrides=self._parameter_overrides,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        global_parameter_overrides=self._global_parameter_overrides,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/lib/providers/sam_stack_provider.py", line 274, in get_stacks
    lang_ext_result = expand_language_extensions(template_dict, parameter_values=parameter_values)
  File "/Users/ta.ishikawa/.pyenv/versions/3.13.11/lib/python3.13/site-packages/samcli/lib/cfn_language_extensions/sam_integration.py", line 555, in expand_language_extensions
    raise InvalidSamDocumentException(str(e)) from e

An unexpected error was encountered while executing "sam build".
Search for an existing issue:
https://github.com/aws/aws-sam-cli/issues?q=is%3Aissue+is%3Aopen+Bug%3A%20sam%20build%20-%20InvalidSamDocumentException
Or create a bug report:
https://github.com/aws/aws-sam-cli/issues/new?template=Bug_report.md&title=Bug%3A%20sam%20build%20-%20InvalidSamDocumentException

Expected result:

Build succeeds. sam build does not require --parameter-overrides — it should process the template in partial resolution mode, preserving Fn::FindInMap expressions whose keys cannot be resolved locally, and let CloudFormation resolve them at deploy time.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

  1. OS: Mac
  2. sam --version: SAM CLI, version 1.160.0
  3. AWS region: ap-northeast-1
# Paste the output of `sam --info` here
{
  "version": "1.160.0",
  "system": {
    "python": "3.13.11",
    "os": "macOS-15.7.2-arm64-arm-64bit-Mach-O"
  },
  "additional_dependencies": {
    "container_engine": "Docker(v29.3.1)",
    "aws_cdk": "Not available",
    "terraform": "1.14.8"
  },
  "available_beta_feature_env_vars": [
    "SAM_CLI_BETA_FEATURES",
    "SAM_CLI_BETA_BUILD_PERFORMANCE",
    "SAM_CLI_BETA_TERRAFORM_SUPPORT",
    "SAM_CLI_BETA_PACKAGE_PERFORMANCE",
    "SAM_CLI_BETA_UV_PACKAGE_MANAGER"
  ]
}

Root cause analysis:

The bug is in samcli/lib/cfn_language_extensions/resolvers/fn_find_in_map.py.
When sam build is invoked without --parameter-overrides, the ENV parameter has no value in context.parameter_values and no Default in the template. FnRefResolver correctly returns {"Ref": "ENV"} (the unresolved dict) in PARTIAL mode. However, FnFindInMapResolver then validates the resolved key with isinstance(top_key, str) and unconditionally raises InvalidTemplateException regardless of resolution mode:

# Validate resolved keys are strings
if not isinstance(map_name, str):
raise InvalidTemplateException("Fn::FindInMap layout is incorrect")
if not isinstance(top_key, str):
raise InvalidTemplateException("Fn::FindInMap layout is incorrect")
if not isinstance(second_key, str):
raise InvalidTemplateException("Fn::FindInMap layout is incorrect")

This is inconsistent with FnRefResolver, which correctly handles the partial mode case:

if self.context.resolution_mode == ResolutionMode.FULL:
raise UnresolvableReferenceError("Ref", ref_target)
# In partial mode, preserve the reference
return {"Ref": ref_target}

Notably, ResolutionMode.PARTIAL is the documented default for SAM CLI integration (models.py: "Use this mode for SAM integration where resource references cannot be resolved locally"), and process_template_for_sam_cli explicitly sets resolution_mode=ResolutionMode.PARTIAL. The cfn_language_extensions module did not exist in 1.159.1, so this is a new regression (likely introduced by #8637).

Proposed Fix

In fn_find_in_map.py, mirror the FnRefResolver pattern — preserve the original Fn::FindInMap expression when in PARTIAL mode and a key cannot be resolved to a string:

# fn_find_in_map.py (proposed fix)
if not isinstance(map_name, str) or not isinstance(top_key, str) or not isinstance(second_key, str):
    from samcli.lib.cfn_language_extensions.models import ResolutionMode
    if self.context.resolution_mode == ResolutionMode.PARTIAL:
        return value  # preserve as-is; CloudFormation will resolve at deploy time
    raise InvalidTemplateException("Fn::FindInMap layout is incorrect")

Additional notes

  • sam validate passes on the same template (different code path, not affected by this bug)
  • Workaround: use sam build --config-env stg so ENV=stg is passed as a parameter override — but this breaks the common workflow of building once for all environments

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions