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

Getting "stream is not readable" since 4.16.0 #693

Open
lightpriest opened this issue Dec 5, 2024 · 0 comments
Open

Getting "stream is not readable" since 4.16.0 #693

lightpriest opened this issue Dec 5, 2024 · 0 comments

Comments

@lightpriest
Copy link

lightpriest commented Dec 5, 2024

The #692 PR introduced a bug when using with express and an async middleware: the IncomingMessage/Request (stream) is marked as not readable and fails when used with body-parser (for example).

Affected version: 4.16.0
Express version: 4 (didn't test it on 5)
Body parser version: 1.20.3

For the code attached, running with 4.15.0 yields:

{
  statusCode: 200,
  body: 'Hello World!',
  isBase64Encoded: false,
  headers: {
    'x-powered-by': 'Express',
    'content-type': 'text/html; charset=utf-8',
    'content-length': '12',
    etag: 'W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"'
  }
}

Running with 4.16.0 yields:

{
  statusCode: 500,
  body: '<!DOCTYPE html>\n' +
    '<html lang="en">\n' +
    '<head>\n' +
    '<meta charset="utf-8">\n' +
    '<title>Error</title>\n' +
    '</head>\n' +
    '<body>\n' +
    '<pre>InternalServerError: stream is not readable<br> &nbsp; &nbsp;at readStream (node_modules/raw-body/index.js:185:17)<br> &nbsp; &nbsp;at getRawBody ... (same as below)' +
    '</body>\n' +
    '</html>\n',
  isBase64Encoded: false,
  headers: {
    'x-powered-by': 'Express',
    'content-security-policy': "default-src 'none'",
    'x-content-type-options': 'nosniff',
    'content-type': 'text/html; charset=utf-8',
    'content-length': 1262
  }
}
InternalServerError: stream is not readable
    at readStream (node_modules/raw-body/index.js:185:17)
    at getRawBody (node_modules/raw-body/index.js:116:12)
    at read (node_modules/body-parser/lib/read.js:79:3)
    at jsonParser (node_modules/body-parser/lib/types/json.js:138:5)
    at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (node_modules/express/lib/router/index.js:328:13)
    at node_modules/express/lib/router/index.js:286:9
    at Function.process_params (node_modules/express/lib/router/index.js:346:12)
    at next (node_modules/express/lib/router/index.js:280:10)
    at src/example.ts:10:3

Code to reproduce:

import serverlessExpress from '@codegenie/serverless-express';
import express from 'express';
import bodyParser from 'body-parser';
import { promisify } from 'node:util';

const app = express();

app.use(async (req, res, next) => {
  // Remove this line to "remove the problem"
  await promisify(setTimeout)(1000);
  next();
});

app.use(bodyParser.json());

app.use((req, res) => {
  res.send('Hello World!');
});

const serverlessExpressInstance = serverlessExpress({ app });

export async function handler(event: any, context: any, callback: any) {
  return serverlessExpressInstance(event, context, callback);
}

handler(
  {
    version: '2.0',
    rawPath: '/path/to/resource',
    headers: {
      "Content-Type": "application/json",
      "Content-Length": "2",
    },
    requestContext: {
      http: {
        method: 'POST',
        path: '/path/to/resource',
        protocol: 'HTTP/1.1',
        sourceIp: '192.168.0.1/32',
        userAgent: 'agent',
      },
    },
    body: "{}",
    isBase64Encoded: false,
  },
  {} as any,
  () => {},
)
  .then(console.log.bind(console))
  .catch(console.error.bind(console));

I believe this is the culprit. Express doesn't return a promise from the handle function, so if there's a middleware that starts an async operation the function will return and the stream will be marked as not readable.

  await framework.sendRequest({ app, request, response })
  markHttpRequestAsCompleted(request) // <-- maybe this should be moved down to after the the stream completes?
  await waitForStreamComplete(response)

Small note, initially I had trouble finding this because I thought we were actually using vendia's serverless-express version. After fiddling with it for a couple of hours I realized it was actually "exporting" codegenie's version. So leaving this note here, in case someone else thinks they're using vendia's.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant