getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.78k stars 1.53k forks source link

Sentry.wrapHandler breaks streaming Lambda handlers #12815

Open zmillman opened 2 weeks ago

zmillman commented 2 weeks ago

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/aws-serverless

SDK Version

8.15.0

Framework Version

No response

Link to Sentry event

No response

SDK Setup/Reproduction Example

Sentry.init({ dsn: process.env.SENTRY_DSN });

Steps to Reproduce

  1. Define an AWS Lambda running with the Node 20.x runtime & configure the SENTRY_DSN env variable:
import * as Sentry from "@sentry/aws-serverless";

Sentry.init({ dsn: process.env.SENTRY_DSN });

// awslambda.streamifyResponse is patched into the global object by the lambda runtime
// https://docs.aws.amazon.com/lambda/latest/dg/configuration-response-streaming.html
export const handler = Sentry.wrapHandler(
  awslambda.streamifyResponse(async function (event, responseStream, _context) {

    responseStream.write("hello");
    responseStream.end();
  })
);
  1. Make a request (any payload)
  2. Check Lambda logs for error

Expected Result

Code should execute identically as if there had been no Sentry.wrapHandler (returning "hello")

Actual Result

Error logs from code above:

2024-07-09T00:38:31.701Z    a203c0fb-7d33-4a3f-b5af-f76ed67423e6    ERROR   Invoke Error    
{
    "errorType": "TypeError",
    "errorMessage": "responseStream.write is not a function",
    "stack": [
        "TypeError: responseStream.write is not a function",
        "    at file:///var/task/index.js:299031:20",
        "    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)",
        "    at async processResult (file:///var/task/index.js:10:14)"
    ]
}

My guess is that wrapHandler wasn't written to detect the streaming Lambda handler which takes different arguments than the default handler.

The Sentry docs have this snippet:

exports.handler = Sentry.wrapHandler(async (event, context) => {
  // Your handler code
});

...but the AWS streaming handler expects the second argument to be responseStream (not context)

chargome commented 2 weeks ago

Hey @zmillman, thanks for reaching out. Currently our wrapHandler function does not support streamifyResponse. If you still want to use wrapHandler make sure you pass a function that takes the correct arguments.

We will put this issue onto our backlog to support streamifyResponse.