CORS header ‘Access-Control-Allow-Origin’ missing from response when using Serverless Framework and AWS

I’m using Serverless Framework to manage all of my API ressources. I followed the official documentation in order to setup CORS correctly.

Here’s how I’ve defined the function on the serverless.yml file:

  get-buyer:
    handler: 'src/endpoints/buyers/getBuyer/getBuyer.handler'
    events:
      - http:
          method: GET
          path: '/buyers/{buyerEmail}'
          request:
            parameters:
              paths:
                buyerEmail: true
          cors:
            origin: 'http://localhost:3000'
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
              - X-Amz-User-Agent
              - X-Amzn-Trace-Id
              - X-Forwarded-For
          operationId: 'get-buyer'
    tags:
      triggered-entity: buyer

Here’s my AWS Lambda function handler code:

export const handler = async (event: APIGatewayProxyEvent) => {
  try {
    const buyerEmail = event.pathParameters?.buyerEmail;
    const tableName = process.env.DYNAMODB_MAIN_TABLE_NAME;

    const parsedBuyerEmail = parse(buyerEmailSchema, buyerEmail);
    const parsedTableName = parse(tableNameSchema, tableName);

    const buyer = await getBuyerFromDdbTable(parsedTableName, parsedBuyerEmail);

    return {
      statusCode: 200,
      headers: {
        'Access-Control-Allow-Origin': 'http://localhost:3000',
        'Access-Control-Allow-Credentials': true,
      },
      body: JSON.stringify({
        buyer,
      }),
    };
  } catch (error) {
    return inferRequestResponseFromError(error);
  }
};

Whenever I send a request to that endpoint I constantly get an 502 BAD GATEWAY:

Here’s the request headers:

GET /dev/buyers/dankramirez@outlook.com HTTP/2
Host: hre46tar8b.execute-api.us-east-1.amazonaws.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0
Accept: application/json, text/plain, */*
Accept-Language: en-US
Accept-Encoding: gzip, deflate, br
Origin: http://localhost:3000
Connection: keep-alive
Referer: http://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

Here’s the response headers:

HTTP/2 502 
content-type: application/json
content-length: 36
date: Wed, 14 Feb 2024 19:18:30 GMT
x-amzn-requestid: 8271d3e8-e0ee-4ab9-9ac6-8bfee2daaa06
x-amzn-errortype: InternalServerErrorException
x-amz-apigw-id: TI_A1HNwIAMECYA=
x-cache: Error from cloudfront
via: 1.1 d2a8ed168561f3bc7e1197e90d2c7298.cloudfront.net (CloudFront)
x-amz-cf-pop: BOG50-P1
x-amz-cf-id: 3XCl8K8fJlBfxsqWZikr1D3XPtZVjsNW7DA3ak0-wbmlfC7nSngsEA==
X-Firefox-Spdy: h2

Here’s what is being captured by CloudWatch for that specific Lambda:

2024-02-14T19:42:45.413Z	undefined	ERROR	Uncaught Exception 	
{
    "errorType": "TypeError",
    "errorMessage": "Invalid URL",
    "code": "ERR_INVALID_URL",
    "input": "MISSING",
    "stack": [
        "TypeError: Invalid URL",
        "    at new URL (node:internal/url:775:36)",
        "    at r (/var/task/src/endpoints/buyers/getBuyer/getBuyer.js:49:133479)",
        "    at w1e (/var/task/src/endpoints/buyers/getBuyer/getBuyer.js:49:133353)",
        "    at new t (/var/task/src/endpoints/buyers/getBuyer/getBuyer.js:49:129579)",
        "    at Object.<anonymous> (/var/task/src/endpoints/buyers/getBuyer/getBuyer.js:53:13737)",
        "    at Module._compile (node:internal/modules/cjs/loader:1376:14)",
        "    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)",
        "    at Module.load (node:internal/modules/cjs/loader:1207:32)",
        "    at Module.load (/opt/nodejs/node_modules/@serverless/sdk/index.js:3505:20)",
        "    at Module._load (node:internal/modules/cjs/loader:1023:12)"
    ]
}

I’m pretty sure the error is being returned by AWS API Gateway and not my function handler. I’ve debugged the function and none of the code is being executed. I also tried using something like export const handler = middy().use(cors()).handler(getBuyer); while using middy middleware to automatically add those headers to the response, but it does not work at all.

Any answer pointing to the solution will be really helpful, thanks!