Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't throw an error on undefined response or event #1122

Closed
wants to merge 3 commits into from

Conversation

phawxby
Copy link

@phawxby phawxby commented Nov 1, 2023

Closes #1121

It appears that normalizeHttpResponse() in the event of undefined or an empty object creates new objects and returns them. This function is relying on side effects for the changes so if new objects are created they're not seen. The result is that if an undefined object is passed in you get an error. It should probably be more like

Comment on lines 14 to 15
request.event ??= {}
request.event.headers ??= {}
Copy link
Member

Choose a reason for hiding this comment

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

Event normalization should be in https://github.com/middyjs/middy/blob/main/packages/http-event-normalizer/index.js.
However,

  1. How are you triggering a lambda without an event?
  2. How are you triggering a lambda without headers in an HTTP event?

Copy link
Author

Choose a reason for hiding this comment

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

Good question, I'm incrementally making my way through the cloudwatch logs to try and figure that out. I believe the inner code is throwing an error, returning something bad, then the response serialiser is trying to handle it but then throwing an error too, so I can't actually see the inner error right now.

So while clearly I need to fix the inner code I feel like it makes sense to make the serialiser a bit more fault tolerant so the inner error can be seen.

ERROR	Invoke Error 	
{
    "errorType": "TypeError",
    "errorMessage": "Cannot read properties of undefined (reading 'Accept')",
    "stack": [
        "TypeError: Cannot read properties of undefined (reading 'Accept')",
        "    at httpResponseSerializerMiddlewareAfter (/var/task/handler.js:101142:50)",
        "    at runMiddlewares (/var/task/handler.js:97057:23)",
        "    at async runRequest (/var/task/handler.js:97035:7)"
    ]
}

I've moved the code as suggested and gone the route of using a null conditional instead.

Copy link
Author

Choose a reason for hiding this comment

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

I found the issue this morning and it was relating to the way the data was being formatted when being passed into an integration test. It probably would've been easier to see had this outer error not occurred.

Copy link
Member

Choose a reason for hiding this comment

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

After some refection, I opted to make a different change that had the same affect that was more consistent with other middlewares. See 4.6.6

@@ -9,7 +9,7 @@ const defaults = {
const httpResponseSerializerMiddleware = (opts = {}) => {
const { serializers, defaultContentType } = { ...defaults, ...opts }
const httpResponseSerializerMiddlewareAfter = async (request) => {
normalizeHttpResponse(request)
request.response = normalizeHttpResponse(request)
Copy link
Member

@willfarrell willfarrell Nov 8, 2023

Choose a reason for hiding this comment

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

It appears that normalizeHttpResponse() in the event of undefined or an empty object creates new objects and returns them. This function is relying on side effects for the changes so if new objects are created they're not seen. The result is that if an undefined object is passed in you get an error. It should probably be more like

See https://github.com/middyjs/middy/blob/main/packages/util/__tests__/index.js#L573
I don't see why this is needed.

@@ -21,6 +21,7 @@ const httpEventNormalizerMiddleware = () => {
// event.headers ??= {} // Will always have at least one header
Copy link
Member

Choose a reason for hiding this comment

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

@phawxby Did you see this comment?

I was asking How are you triggering a lambda without headers in an HTTP event? to better understand how you're able to create an HTTP event without any headers. As far as I'm aware, it's impossible. I'm really curious how you're able to trigger lambda through APIG/ALB/Function URL without headers.

Others have run into something similar which turned out be their unit tests being incomplete.

Copy link
Author

Choose a reason for hiding this comment

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

Sorry @willfarrell, I hadn't seen this. I was using a regular @aws-sdk/client-lambda InvokeCommand without supplying headers in the payload

Copy link
Member

Choose a reason for hiding this comment

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

Ah, that make so much sense now. Middlewares with http-* were built to be used with APIG/ALB/Function URL and the event they create. These middlewares are overkill for a lambda that gets called directly with Invoke.

I'm going to close this PR for now then.

@willfarrell willfarrell closed this Nov 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

TypeError: Cannot read properties of undefined (reading 'Accept')
2 participants