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

Bug: Duplicate method 'OPTIONS' error

Open royassis opened this issue 5 months ago • 1 comments

SAM CLI, version 1.139.0 Linux

When there are both POST and PUT, api events in AWS::Serverless::Function resource + Cors section in an AWS::Serverless::Api resource.

I get an error:

Resource handler returned message: "Errors found during import:
Duplicate method 'OPTIONS' on resource at path '/datasets'
(Service: ApiGateway, Status Code: 400, Request ID:
xxx) (SDK Attempt Count: 1)"
(RequestToken: xxx,
HandlerErrorCode: InvalidRequest)

This is the template file :

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

Globals:
  Function:
    Timeout: 60
    MemorySize: 512
    Tracing: Active
    Tags:
      GitRev: !Ref GitRev
    Environment:
      Variables:
        DbName: !Ref DbName
        MongoSecretName: !Ref MongoSecretName
        StackName: !Sub ${AWS::StackName}
        POWERTOOLS_SERVICE_NAME: !Sub ${AWS::StackName}
        POWERTOOLS_LOG_LEVEL: INFO
        Environment: !Ref Environment
        GitRev: !Ref GitRev

Parameters:
  DbName:
    Type: String
    Description: Mongodb database name
  MongoSecretName:
    Type: String
    Description: AWS secret name containing Mongodb server secrets
  VPCEndpointId:
    Type: String
    Description: vpc endpoint associated with said APIGW
    AllowedPattern: ^vpce-[A-Za-z0-9]+$
  GitRev:
    Type: String
    Default: ""
  Environment:
    Type: String
    Default: test
    AllowedValues:
      - test
      - prod

Resources:
  AppBackend:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 2048
      PackageType: Image
      Policies:
        - AWSSecretsManagerGetSecretValuePolicy:
            SecretArn: !Sub arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${MongoSecretName}*
      Events:
        ListDatasets:
          Type: Api
          Properties:
            Path: /datasets
            Method: post
            RestApiId: !Ref MyRestApi
            Auth:
              Authorizer: MyLambdaRequestAuth
        GetDataset:
          Type: Api
          Properties:
            Path: /datasets/{dataset_id}
            Method: get
            RestApiId: !Ref MyRestApi
            Auth:
              Authorizer: MyLambdaRequestAuth
        PutDataset:
          Type: Api
          Properties:
            Path: /datasets/
            Method: put
            RestApiId: !Ref MyRestApi
            Auth:
              Authorizer: MyLambdaRequestAuth
        DeleteDataset:
          Type: Api
          Properties:
            Path: /datasets/{dataset_id}
            Method: delete
            RestApiId: !Ref MyRestApi
            Auth:
              Authorizer: MyLambdaRequestAuth
#        ListStudies:
#          Type: Api
#          Properties:
#            Path: /studies
#            Method: post
#            RestApiId: !Ref MyRestApi
#            Auth:
#              Authorizer: MyLambdaRequestAuth
#        GetStudy:
#          Type: Api
#          Properties:
#            Path: /studies/{study_id}
#            Method: get
#            RestApiId: !Ref MyRestApi
#            Auth:
#              Authorizer: MyLambdaRequestAuth
#        PutStudy:
#          Type: Api
#          Properties:
#            Path: /studies/
#            Method: put
#            RestApiId: !Ref MyRestApi
#            Auth:
#              Authorizer: MyLambdaRequestAuth
#        DeleteStudy:
#          Type: Api
#          Properties:
#            Path: /studies/{study_id}
#            Method: delete
#            RestApiId: !Ref MyRestApi
#            Auth:
#              Authorizer: MyLambdaRequestAuth
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./functions/be


  MsAuthorizer:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 2048
      CodeUri: functions/authorizer/src
      Handler: app.handler
      Runtime: python3.12

  MyRestApi:
    Type: AWS::Serverless::Api
    Properties:
#      BinaryMediaTypes:
#        - application/octet-stream
      Cors:
        AllowOrigin: '''*'''
        AllowHeaders: '''Content-Type,Authorization,X-Amz-Date'''
        MaxAge: '''300'''
      StageName: v1
      TracingEnabled: true
      GatewayResponses:
        MISSING_AUTHENTICATION_TOKEN:
          ResponseTemplates:
            application/json: '{"message": "missing authentication token error OR
              unsupported API method or resource" }'
      MethodSettings:
        - HttpMethod: '*'
          LoggingLevel: INFO
          ResourcePath: /*
          DataTraceEnabled: true
          CachingEnabled: false
          MetricsEnabled: true
      EndpointConfiguration:
        Type: PRIVATE
        VPCEndpointIds:
          - !Ref VPCEndpointId
      Auth:
        Authorizers:
          MyLambdaRequestAuth:
            FunctionPayloadType: TOKEN
            Identity:
              Header: Authorization
            FunctionArn:
              !GetAtt MsAuthorizer.Arn
        ResourcePolicy:
          CustomStatements:
            - Effect: Allow
              Action: execute-api:Invoke
              Resource: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*/*/*"
              Principal: '*'
              Condition:
                StringEquals:
                  aws:SourceVpce: !Ref VPCEndpointId

royassis avatar Jul 24 '25 06:07 royassis

I found the issue

put event path: datasets

post event path: datasets/

royassis avatar Jul 24 '25 07:07 royassis