serverless-application-model icon indicating copy to clipboard operation
serverless-application-model copied to clipboard

BasePathMapping deployment error: Invalid stage identifier specified

Open cluggas opened this issue 6 years ago • 30 comments

I have a SAM template deploying three resources: An ApiGateway, a Lambda Function and a ApiGateway BasePathMapping.

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Parameters:
      StageName:
        Type: String
    Resources:
      api:
        Type: AWS::Serverless::Api
        Properties:
          DefinitionBody: ...
          StageName: !Ref StageName
      apidomain:
        Type: AWS::ApiGateway::BasePathMapping
        Properties:
          DomainName: mydomain.com
          RestApiId: !Ref api
          Stage: !Ref StageName
      lambda:
        Type: AWS::Serverless::Function
        Properties: ...

There is one parameter to the template called StageName, and this is used in two places:

  1. The StageName for the ApiGateway
  2. The Stage value for the BasePathMapping

When this stack is deployed, Cloud Formation deploys things in a strange order. It deploys the Api Gateway before the BasePathMapping, which you would expect, but deploying the ApiGateway stage is a separate step. It tries to deploy the BasePathMapping before the ApiGateway Stage, which results in the error:

Invalid stage identifier specified

This is totally underdtandable given it has not been created yet.

I have tried using the DependsOn property on the BasePathMapping resource to force it to get created after the ApiGateway. It does, but not after the ApiGateway stage.

Does anyone know a way around this? It feels like a bug with the AWS::Serverless::Api resource type. It clearly needs to create a Gateway and a Stage, but the should be done sequentially not not allow the BasePathMapping to be created in between.

Work arounds I don't like include:

  1. A two stage deployment. First without the BasePathMapping, then with it

cluggas avatar Sep 01 '17 14:09 cluggas

I got a workaround for this.. Apparently when using SAM (aws cloudformation deploy) it uses the transform (Transform: AWS::Serverless-2016-10-31) rule set in your template to generate all kind of "extra" resources. One of them is a aws::ApiGateway::stage resource. The name of this resource is ServerlessApiStage where ServerlessApi is the name of the AWS::Serverless::Api resource.

jvanbrunschot-coolblue avatar Dec 13 '17 21:12 jvanbrunschot-coolblue

This might be a documentation issue. We are using a standard mechanism for constructing resource names. You should be able to use "DependsOn" to chain the resource creation in correct order. I will update the docs to explain how the resource names are created.

sanathkr avatar Jan 16 '18 19:01 sanathkr

I really don't understand why it's trying to redeploy my API gateway stages in the first place. If my function that an API gateway resource is using is pointing to ":Latest" then why do we need to redeploy?

JimLynchCodes avatar Jun 25 '18 21:06 JimLynchCodes

I'm having similar issue.

I tried using DependsOn to specify that the BasePathMapping depends on my AWS::ApiGateway::DomainName and AWS::Serverless::Api resource, but it is still created before Stage is created. I'm guessing that's because Stage is a separate resource outside of AWS::Serverless::Api.

darrendao avatar Jul 17 '18 00:07 darrendao

Thanks to @jvanbrunschot-coolblue 's comment, I was able to find a workaround. It looks like ServerlessApiStage is indeed a separate resource outside of AWS::Serverless::Api, and is generated by the transform function. So my workaround is to figure out what the generated resource name would be for the stage and specify that in the DependsOn section of the AWS::ApiGateway::BasePathMapping resource.

darrendao avatar Jul 17 '18 00:07 darrendao

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage.

Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

rodmaz avatar Jul 22 '18 01:07 rodmaz

Hi, I had to add apiStage and not only Stage.

aws-cli/1.15.66 SAM CLI, version 0.5.0

stijnvanrenterghem avatar Sep 13 '18 13:09 stijnvanrenterghem

Hi, So i was stuck in the same scenario and after a lot of help from the above comments and a little trial and error on my end. The format of the aws::ApiGateway::stage is => (name of the serverless api resource)(stage name)Stage

nikhil1007 avatar Oct 17 '18 07:10 nikhil1007

Adding a DomainName property to the AWS::Serverless::API resources which configures this all for you is probably what we want here.

brettstack avatar Oct 22 '18 14:10 brettstack

Having Domain and Certificate parameters makes sense to me. If Certificate is not passed AWS::Serverless::API could create AWS::CertificateManager::Certificate resource too.

ericofusco avatar Jan 22 '19 13:01 ericofusco

Any update on this? Would great to make this easier. Ran into this problem again recently. If need to understand the inner of an abstraction (i.e SAM) in order to use it then surely it's not doing its job?

tkeeber avatar Jan 25 '19 10:01 tkeeber

I added an RFC for this here https://github.com/awslabs/serverless-application-model/issues/783. I'm going to close out this issue as a workaround has been posted, and we have a path forward to a simpler solution.

brettstack avatar Jan 25 '19 18:01 brettstack

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage.

Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

THIS IS IT THANKS FOR TAKING ME OUT OF MY DESPERATION PIT

alfredo-g-zapiola avatar Aug 13 '19 00:08 alfredo-g-zapiola

For me the solution was:

Resources:
  Api:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: NONE
  BasePathMapping:
    Type: AWS::ApiGateway::BasePathMapping
    Properties:
      DomainName: !Ref GatewayDomain
      RestApiId: !Ref Api
      Stage: !Ref Api.Stage

Notice the BasePathMapping.Stage is set to !Ref Api.Stage which creates tight coupling and removes potential user errors such as typos.

ca0abinary avatar Aug 13 '19 15:08 ca0abinary

@ca0abinary Thanks for the comment! This will be a really good addition to the examples folder. Reopening this issue.

praneetap avatar Aug 20 '19 17:08 praneetap

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage. Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

THIS IS IT THANKS FOR TAKING ME OUT OF MY DESPERATION PIT

Thank you it worked for me SAM 0.22.0 I had the same issue: just refer the object with the same name plus stage. To verify you are referring the right resources compiled by sam, I suggest to run sam validate --debug and verify the name :-) thank you again!

made2591-eb avatar Oct 18 '19 15:10 made2591-eb

If anyone is using an Http protocol API and the AWS::ApiGatewayV2:ApiMapping I solved this by referencing ServerlessHttpApiApiGatewayDefaultStage for stage.

  ApiMapping:
    Type: AWS::ApiGatewayV2::ApiMapping
    Properties:
      ApiId: !Ref ServerlessHttpApi
      DomainName: !Ref ApiDomainName
      Stage: !Ref ServerlessHttpApiApiGatewayDefaultStage

mpvosseller avatar Feb 19 '20 17:02 mpvosseller

@ca0abinary Use "!Ref Api.Stage" as reference works here!! Thanks!!!

Delermando avatar Mar 27 '20 14:03 Delermando

it works perfect for me Use "!Ref Api.Stage"

knowledgeshare99 avatar May 14 '20 11:05 knowledgeshare99

I had this issue and not even AWS Support knew the answer 🤦

@ca0abinary 's solution worked perfectly.

paul-uz avatar Feb 10 '21 14:02 paul-uz

This worked for me: https://github.com/aws/serverless-application-model/issues/192#issuecomment-351527399

Apparently this is still an issue.

tcanady avatar Feb 19 '21 02:02 tcanady

Worked for me as well. Thank you.

SaundersB avatar Apr 03 '21 23:04 SaundersB

Based on the link below this should have been fixed by adding a DependsOn to <api‑LogicalId><stage‑name>Stage (as documented in this link: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-api.html)

Template format error: Unresolved resource dependencies [RestAPIGatewaydevelopmentStage] in the Resources block of the template

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Parameters:
  APIStageName:
    Type: 'AWS::SSM::Parameter::Value<String>'
    Description: The name of the stage to deploy the API to.
    Default: /account/environment
Resources:    
  RestAPIGateway:
    Type: AWS::ApiGateway::RestApi
...
  APICustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn: 
     - RestAPIGatewaydevelopmentStage
    Properties:
      DomainName: !Ref APICustomDomain
      RestApiId: !Ref RestAPIGateway
      Stage: !Ref APIStageName

It is hard to believe that this issue has not been addressed after almost 5 years. It seems that adding an explicit dependson on the stage generated during translation should fix this.

yortch avatar Jul 22 '22 21:07 yortch

We got this to work by adding a WaitConditionHandle on the suggested stage name. Not clear why this does not work directly on the DependsOn, but in case it matters we are using AWS CLI 2.0 from CodeBuild project using aws/codebuild/standard:5.0 image.

  StageCreated:
    Type: AWS::CloudFormation::WaitConditionHandle
    Metadata:
      Created: !Sub RestAPIGateway${APIStageName}Stage

  APICustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn: 
     - StageCreated

The impact of this issue is that since it's a timing issue it some times work, so imagine it works in dev/test environments and it happens to fail in the production deployment, that would be a very bad experience.

yortch avatar Jul 26 '22 13:07 yortch

The workaround does not seem to work for my client. I think the difference is that we're using a RestApi vs Api and maybe that's why the workaround doesn't work for us. Does anybody still have the issue?

yaminir avatar Sep 13 '22 17:09 yaminir

Thank you @yaminir, I think we were finally able to fix this permanently by adding an explicit Stage resource, which allowed us to create an explicit dependency:

  RestAPIGateway:
    Type: AWS::ApiGateway::RestApi
    ...
  ApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId: !Ref RestAPIGateway
  APIGatewayStage:
    Type: "AWS::ApiGateway::Stage"
    Properties:
      DeploymentId: !Ref ApiGatewayDeployment
      RestApiId: !Ref RestAPIGateway
      StageName: !Ref APIStageName
  APICustomDomainMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn:
     - APIGatewayStage
    Properties:
      DomainName: !Ref APICustomDomain
      RestApiId: !Ref RestAPIGateway
      Stage: !Ref APIStageName

yortch avatar Sep 19 '22 19:09 yortch

I ran into this when adding a custom domain name, resolved simply with DependsOn the API like:

  MyCustomDomainName:
    Type: AWS::ApiGateway::DomainName
    Properties:
      RegionalCertificateArn: arn:aws:acm:eu-west-1:2345678:certificate/0000000-11111-2222-3333-444444444
      DomainName: some-api.prd.some-domain.com
      SecurityPolicy: TLS_1_2
      EndpointConfiguration:
        Types:
          - REGIONAL
    DependsOn:
     - yourRestAPIResource

Leigh-M avatar Sep 26 '22 17:09 Leigh-M

Hello everyone,

Yes this error is mostly due the stage not being created yet. So youre trying to map the custom domain to something that doesnt exist. In my case i am using serverless framework and i could not find the mapping reference resource. In any case after lot of testing, using dependson with these solved for me.

DependsOn: - APIGatewayCustomDomain - YourLambdaFunction - ApiGatewayRestApi - ApiGatewayMethodAny - ApiGatewayMethodProxyVarAny

vsimoesbh avatar Nov 19 '22 12:11 vsimoesbh

Indeed it seems to be a bug, which disregards the dependencies between these resources. I am using SAM CLI 0.4.0 and AWS CLI 1.11.131 and had the same problem. In my case the final template generate by Cloudformation produced the stage name as a concatenation of my API logical name and word Stage: <myApiLogicalName>Stage.

Fixed the problem by adding a DependsOn on AWS::ApiGateway::BasePathMapping as seen below:

  # ########################################################################
  # Mobile API
  apiMobile:
    Type: 'AWS::Serverless::Api'
    Properties:
      Name: mobile-api
      StageName: !FindInMap [ApiStage, !Ref Environment, stage]
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: 's3://<redacted>/swagger.yaml'
      EndpointConfiguration: REGIONAL

  # ###################################################################
  # Base Path Mapping
  apiBasePathMapping:
    Type: 'AWS::ApiGateway::BasePathMapping'
    Properties:
      BasePath: v1.0
      Stage: !FindInMap [ApiStage, !Ref Environment, stage]
      DomainName:
        'Fn::Sub':
          - 'mobile-api${Suffix}.<redacted>'
          - Suffix: !FindInMap
            - EnvironmentShort
            - !Ref Environment
            - suffix
      RestApiId: !Ref apiMobile
    DependsOn:
      - apiMobileStage  <------ Added explicit dependency

@rodmaz You saved my life, I was also hit by this

maxidorius avatar Feb 09 '23 13:02 maxidorius

This was fixed for me by adding a Depends on

like follows


RestApi:
    Type: AWS::Serverless::Api
ApiBasePathMapping
   Type: AWS::ApiGateway::BasePathMapping
   DependsOn: 
     -RestApiStage // the name of the AWS::Serverless::Api appeneded with Stage here the name is RestApi(line No 1) and the stage is appended

rgplvr avatar Feb 11 '24 16:02 rgplvr