-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
Issue description
I am trying to share an API Gateway V2 between all the functions in the serverless file. When I tried using provider.httpApi.apiId["Fn::ImportValue"] with an export name defined in the same serverless.yml in resources.Resources.Outputs it failed with an error saying that it cannot resolve the export. When I modified the config to be as in the issue context, the deployment succeeds, CF stack is marked as CREATE_COMPLETE or UPDATE_COMPLETE in the AWS console, but serverless deploy fails with an error seen in the issue context. This is pretty annoying because I have to swallow this error in my github actions pipeline, and also the command does not print the stack outputs when it errors out, which is another problem I need to solve now.
Also the command serverless deploy prints the following warning at the beginning when ran:
[!] Invalid configuration encountered
at 'provider.httpApi.id': must have required property 'Fn::ImportValue'
at 'provider.httpApi.id': unrecognized property 'Ref'
Context
Service Overview
- Serverless Framework Version: 4.27.0
- Service Config File: serverless.yml
- Service Name: recipe-scraper
- Service App: recipe-scraper
- Service Runtime: python3.13
- Service Stage: prod
- Service Region: eu-north-1
- Error Code: UNABLE_TO_RESOLVE_HTTP_API_ID
Service Path
[REDACTED]
Command
deploy --param recipeTTL=5d,recipeReadyNotificationBody=Ready,recipeReadyNotificationTitle=Recipe,aiBaseUrl=https://api.openai.com/v1,promptIdPL=[REDACTED],maxAiParseRetryCount=4,promptIdEN=[REDACTED],domainName=[REDACTED],aiModelName=gpt-5-nano,--verbose true
Error Message
Could not resolve provider.httpApi.id parameter. Expected params.ApiId to be a string
Error Stacktrace
at file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1117:3845
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async Promise.all (index 1)
at async aws:info:gatherData (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1117:12599)
at async PluginManager.runHooks (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1372:11105)
at async PluginManager.invoke (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1372:11874)
at async PluginManager.spawn (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1372:12236)
at async PluginManager.runHooks (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1372:11105)
at async PluginManager.invoke (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1372:11874)
at async PluginManager.run (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1372:12607)
at async Serverless.run (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1379:10524)
at async runFramework (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1406:1781)
at async TraditionalRunner.run (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1402:28508)
at async route (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1577:2848)
at async Object.run (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1578:3876)
at async run2 (file:///[REDACTED - windows user docs dir]/.serverless/releases/4.27.0/package/dist/sf-core.js:1578:5030)
Service Config
org: maciejcorp
app: recipe-scraper
service: recipe-scraper
provider:
name: aws
runtime: python3.13
stage: prod
region: eu-north-1
architecture: arm64
httpApi:
id: !Ref Gateway
layers:
- !Ref SharedLambdaLayer
functions:
# endpoint handlers
get-recipe:
handler: functions/get_recipe/handler.handler
environment:
DYNAMO_USER_QUOTA_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-UserQuotaTableName
RECIPES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-RecipesTableName
events:
- httpApi:
path: /recipe/{recipeId}
method: get
authorizer:
type: jwt
id:
Ref: ApiGatewayAuthorizer
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:Query
Resource:
- !ImportValue RecipeScraperPermanentResourcesProd-RecipesTableArn
- !ImportValue RecipeScraperPermanentResourcesProd-UserQuotaTableArn
scrape-recipe:
handler: functions/scrape_recipe/handler.handler
events:
- httpApi:
path: /recipe/scrape
method: post
authorizer:
type: jwt
id:
Ref: ApiGatewayAuthorizer
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:Query
Resource:
- !ImportValue RecipeScraperPermanentResourcesProd-RecipesTableArn
- !ImportValue RecipeScraperPermanentResourcesProd-UserQuotaTableArn
- Effect: Allow
Action:
- states:StartExecution
Resource: ${self:resources.Outputs.ProcessIngredientsStepFn.Value}
- Effect: Allow
Action:
- sns:CreatePlatformEndpoint
Resource: ${env:SNS_ANDROID_PLATFORM_APPLICATION_ARN}
environment:
DYNAMO_USER_QUOTA_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-UserQuotaTableName
RECIPES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-RecipesTableName
PROCESS_INGREDIENTS_STEP_FN_ARN: ${self:resources.Outputs.ProcessIngredientsStepFn.Value}
RECIPE_TTL: ${param:recipeTTL}
SNS_PLARFORM_APPLICATION_ARN__ANDROID: ${env:SNS_ANDROID_PLATFORM_APPLICATION_ARN}
parse-result-webhook:
handler: functions/parse_result_webhook/handler.handler
events:
- httpApi:
path: /ai/webhook
method: post
environment:
DYNAMO_RESPONSES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableName
AI__API_KEY: ${env:AI_API_KEY}
AI__BASE_URL: ${param:aiBaseUrl}
AI__WEBHOOK_SECRET: ${env:AI_WEBHOOK_SECRET}
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
Resource: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableArn
- Effect: Allow
Action:
- states:SendTaskSuccess
- states:SendTaskFailure
Resource: ${self:resources.Outputs.ProcessIngredientsStepFn.Value}
# iternal processing
assemble-recipe:
handler: functions/assemble_recipe/handler.handler
environment:
RECIPES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-RecipesTableName
NOTIFICATION__BODY: ${param:recipeReadyNotificationBody}
NOTIFICATION__TITLE: ${param:recipeReadyNotificationTitle}
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource: !ImportValue RecipeScraperPermanentResourcesProd-RecipesTableArn
- Effect: Allow
Action:
- sns:Publish
- sns:DeleteEndpoint
Resource: ${env:SNS_ANDROID_PLATFORM_APPLICATION_ARN}
parse-ingredient-start:
handler: functions/parse_ingredient_start/handler.handler
environment:
AI__API_KEY: ${env:AI_API_KEY}
AI__BASE_URL: ${param:aiBaseUrl}
AI__MODEL_NAME: ${param:aiModelName}
PROMPT_ID__PL: ${param:promptIdPL}
PROMPT_ID__EN: ${param:promptIdEN}
DYNAMO_RESPONSES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableName
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:PutItem
Resource: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableArn
parse-ingredient-success:
handler: functions/parse_ingredient_success/handler.handler
environment:
AI__API_KEY: ${env:AI_API_KEY}
AI__BASE_URL: ${param:aiBaseUrl}
MAX_RETRY_COUNT: ${param:maxAiParseRetryCount}
DYNAMO_RESPONSES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableName
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:DeleteItem
Resource: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableArn
parse-ingredient-fail:
handler: functions/parse_ingredient_fail/handler.handler
environment:
DYNAMO_RESPONSES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableName
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:DeleteItem
Resource: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableArn
parse-ingr-prep-retry:
handler: functions/parse_ingredient_prepare_for_retry/handler.handler
environment:
DYNAMO_RESPONSES_TABLE_NAME: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableName
iam:
inheritStatements: true
role:
statements:
- Effect: Allow
Action:
- dynamodb:GetItem
Resource: !ImportValue RecipeScraperPermanentResourcesProd-OpenAiResponsesTableArn
# used within processIngredients state machine definition file
custom:
parseIngredientStartFnName: !Ref ParseDashingredientDashstartLambdaFunction
parseIngredientFailFnName: !Ref ParseDashingredientDashfailLambdaFunction
parseIngredientSuccessFnName: !Ref ParseDashingredientDashsuccessLambdaFunction
assembleRecipeFnName: !Ref AssembleDashrecipeLambdaFunction
parseIngredientFailNotificationSNSTopic: !ImportValue RecipeScraperPermanentResourcesProd-OutOfCreditsAdminNotificationsTopic
prepareForRetryFunctionArn: !Ref ParseDashingrDashprepDashretryLambdaFunction
pythonRequirements:
useUv: true
dockerizePip: non-linux
customDomain:
domainName: ${param:domainName}
stage: prod
basePath: prod
createRoute53Record: false
createRoute53IPv6Record: false
endpointType: REGIONAL
apiType: http
autoDomain: true
certificateArn: ${env:DOMAIN_CERTIFICATE_ARN}
stepFunctions:
stateMachines:
processIngredients:
name: ProcessIngredients
definition: ${file(functions/process_ingredients/stateMachine.asl.yml)}
layers:
shared:
path: lib
compatibleArchitectures:
- arm64
compatibleRuntimes:
- python3.13
resources:
Description: "CloudFormation functions template for ${self:service}"
Resources:
Gateway:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: Gateway
ProtocolType: HTTP
DisableExecuteApiEndpoint: true
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
GatewayStage:
Type: AWS::ApiGatewayV2::Stage
Properties:
ApiId: !Ref Gateway
StageName: prod
AutoDeploy: true
GatewayDomainMapping:
Type: AWS::ApiGatewayV2::ApiMapping
Properties:
ApiId: !Ref Gateway
DomainName: ${param:domainName}
Stage: prod
DependsOn: GatewayStage
ApiGatewayAuthorizer:
Type: AWS::ApiGatewayV2::Authorizer
Properties:
AuthorizerResultTtlInSeconds: 0
IdentitySource:
- $request.header.Authorization
Name: cognito-authorizer
ApiId: !Ref Gateway
AuthorizerType: JWT
JwtConfiguration:
Audience:
- Fn::ImportValue: RecipeScraperCognitoProd-UserPoolClient
Issuer:
Fn::Join:
- ""
- - "https://cognito-idp."
- "${opt:region, self:provider.region}"
- ".amazonaws.com/"
- Fn::ImportValue: RecipeScraperCognitoProd-UserPool
Outputs:
ProcessIngredientsStepFn:
Value: !Ref ProcessIngredients
Gateway:
Value: !Ref Gateway
Export:
Name: !Sub "${AWS::StackName}-Gateway"
ApiEndpoint:
Value: !GetAtt Gateway.ApiEndpoint
Export:
Name: !Sub "${AWS::StackName}-ApiEndpoint"
plugins:
- serverless-step-functions
- serverless-domain-manager