Skip to content

Conversation

sdangol
Copy link
Contributor

@sdangol sdangol commented Jul 14, 2025

Summary

This PR removes the nullable type from the md5OfMessageAttributes in the SqsRecordSchema aligning with the @types/aws-lambda package

Changes

  1. Removed the nullable type from the md5OfMessageAttributes property in the SqsRecordSchema
  2. Updated the data in firehose-sqs.json test event to remove the null value of md5OfMessageAttributes

Issue number: #4109


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@pull-request-size pull-request-size bot added the size/XS PR between 0-9 LOC label Jul 14, 2025
@boring-cyborg boring-cyborg bot added parser This item relates to the Parser Utility tests PRs that add or change tests labels Jul 14, 2025
Copy link

boring-cyborg bot commented Jul 14, 2025

Thanks a lot for your first contribution! Please check out our contributing guidelines and don't hesitate to ask whatever you need.
In the meantime, check out the #typescript channel on our Powertools for AWS Lambda Discord: Invite link

Copy link

@dreamorosi dreamorosi self-requested a review July 14, 2025 12:05
Copy link
Contributor

@dreamorosi dreamorosi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thank you for fixing the schema and congrats for your first PR merged in this project 🎉

@dreamorosi dreamorosi merged commit d6cbde0 into aws-powertools:main Jul 14, 2025
54 checks passed
Copy link

boring-cyborg bot commented Jul 14, 2025

Awesome work, congrats on your first merged pull request and thank you for helping improve everyone's experience!

@bboure
Copy link

bboure commented Sep 12, 2025

Hi.

After this "fix", I am getting this error.

{
    "errorType": "ParseError",
    "errorMessage": "Failed to parse SQS Envelope. This error was caused by: [\n  {\n    \"expected\": \"string\",\n    \"code\": \"invalid_type\",\n    \"path\": [\n      \"Records\",\n      0,\n      \"md5OfMessageAttributes\"\n    ],\n    \"message\": \"Invalid input: expected string, received null\"\n  }\n].",
    "name": "ParseError",
    "stack": [
        "ParseError: Failed to parse SQS Envelope. This error was caused by: [",
        "  {",
        "    \"expected\": \"string\",",
        "    \"code\": \"invalid_type\",",
        "    \"path\": [",
        "      \"Records\",",
        "      0,",
        "      \"md5OfMessageAttributes\"",
        "    ],",
        "    \"message\": \"Invalid input: expected string, received null\"",
        "  }",
        "].",
        "    at Object.parse (/node_modules/@aws-lambda-powertools/parser/lib/esm/envelopes/sqs.js:36:19)",
    ]
}

Logging the event shows that I do get this attribute as null

From the logs (strigified payload)

"md5OfMessageAttributes":null

I am not quite sure in what circumstances this occurs, but we should probably revert this change.

Thanks

@dreamorosi
Copy link
Contributor

Hi @bboure, thanks for reporting.

I am not quite sure in what circumstances this occurs

I think this would be helpful to understand if the type and schemas are indeed off on not. For now, as discussed in the linked issue we assumed that the type was correct and we weren't but we also weren't able to reproduce the field being null in a function so we just aligned ourselves with the type.

If you could share steps to reproduce the field being null in Lambda, we'll make sure to verify it and revert the change right away.

@bboure
Copy link

bboure commented Sep 12, 2025

Thanks @dreamorosi

So, here is a snippet of my code that reproduces this issue.

From another Lambda function:

export const sendMessageBatch = async (
  queueUrl: string,
  messages: Array<{
    id: string;
    body: string;
    delayInSeconds?: number;
  }>,
) => {
  const entries: SendMessageBatchRequestEntry[] = messages.map((message) => ({
    Id: message.id,
    MessageBody: message.body,
    DelaySeconds: message.delayInSeconds,
  }));

  const command = new SendMessageBatchCommand({
    QueueUrl: queueUrl,
    Entries: entries,
  });

  await sqsClient.send(command);
};

Usage

const events = [
  { id: '123', body: JSON.stirngify({ foo: 'bar' }) }
];
await sendMessageBatch(NOTIFICATION_QUEUE_URL, events);

After some research, I figured that adding MessageAttributes in SendMessageBatchCommand forces this value to be present and it makes the validation pass.

    Id: message.id,
    MessageBody: message.body,
    // Adding this works  👇
    MessageAttributes: {
      ContentType: { DataType: 'String', StringValue: 'application/json' },
    },
    DelaySeconds: message.delayInSeconds,

@bboure
Copy link

bboure commented Sep 12, 2025

And just in case it's relevant:

NodeJS version: 22
architecture: ARM
Lambda is in a VPC

@dreamorosi
Copy link
Contributor

dreamorosi commented Sep 12, 2025

Ok, thanks - we'll look into it on Monday.

@dreamorosi
Copy link
Contributor

dreamorosi commented Sep 13, 2025

I've looked into it and I'm unable to reproduce the "bug".

I have created a minimal CDK stack with 2 functions and 1 queue that you can find here. You're welcome to clone the repo, deploy the stack, and verify the statements below in your own account.

The producer function uses the code you shared above to publish messages to the queue, while the consumer one is triggered by the queue and uses various combinations of built-in SQS schemas and envelopes to parse the event.

After deploying the stack and triggering the producer (instructions are in the README), you can see from the logs of the consumer function that all parse operations succeed despite the message attributes being empty and the md5OfMessageAttributes field not being present.

After re-reading the PR and remembering what it was about, this makes sense to me, since the PR marks the field as optional() (previously was .optional().nullable()).

As you can see from the git history, since it was introduced, the md5OfMessageAttributes has never been required (link), so the error message you're seeing is probably due to either an older version of Parser (unsure how .optional().nullable() interact with each other) or an override to the schema being applied in your code.

Either way based on the above and the information you provided, I'm not inclined to revert this PR.

@bboure
Copy link

bboure commented Sep 13, 2025

Thanks @dreamorosi

After doing some more tests, comparing with our solution, I finally found how to reproduce. It happens when enabling maxBatchingWindow. See this PR https://github.com/dreamorosi/repro-4165/pull/1/files

{
    "level": "ERROR",
    "message": "Failed to parse SQS event",
    "timestamp": "2025-09-13T13:47:34.199Z",
    "service": "sqs-consumer",
    "sampling_rate": 0,
    "xray_trace_id": "1-68c575f5-0c82ef561607ff44f3e38830",
    "error": {
        "name": "ZodError",
        "location": "file:///var/task/index.mjs:3",
        "message": "[\n  {\n    \"expected\": \"string\",\n    \"code\": \"invalid_type\",\n    \"path\": [\n      \"Records\",\n      0,\n      \"md5OfMessageAttributes\"\n    ],\n    \"message\": \"Invalid input: expected string, received null\"\n  }\n]",
        "stack": "ZodError: [\n  {\n    \"expected\": \"string\",\n    \"code\": \"invalid_type\",\n    \"path\": [\n      \"Records\",\n      0,\n      \"md5OfMessageAttributes\"\n    ],\n    \"message\": \"Invalid input: expected string, received null\"\n  }\n]\n    at new ZodError (file:///var/task/index.mjs:3:23677)\n    at file:///var/task/index.mjs:4:687\n    at e.safeParse (file:///var/task/index.mjs:25:4634)\n    at Runtime.hb [as handler] (file:///var/task/index.mjs:25:22959)\n    at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1206:29)"
    }
}

@dreamorosi
Copy link
Contributor

Interesting!

Before we fix this, let me ask some questions internally. I find it weird that enabling a seemingly unrelated setting in the Event Source Mapping (ESM) causes the field to be omitted or set to null when there're no attributes.

In the meantime I suggest to manually override the field in the schema, or patch the producer like you suggested earlier.

@ajpower
Copy link

ajpower commented Oct 11, 2025

@dreamorosi I can confirm that md5OfMessageAttributes is null when maxBatchingWindow is specified. I did not test without maxBatchingWindow, however.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parser This item relates to the Parser Utility size/XS PR between 0-9 LOC tests PRs that add or change tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Ensure parser schema types are compatible with @types/aws-lambda

5 participants