Erroneously getting 'Bad Request: request should have required property 'headers'' error
See original GitHub issueDescribe the bug i’m building an API in NodeJS. I’ve got an openapispec (see below) that doesn’t throw any errors when validated using editor.swagger.io. It works as expected on localhost. However, after deploying the API on Heroku, I get the following mysterious error:
Bad Request: request should have required property 'headers'
2021-01-14T01:56:41.458079+00:00 app[web.1]: at Object.GET-/liveness-not_provided (/app/node_modules/express-openapi-validator/dist/middlewares/openapi.request.validator.js:92:31)
2021-01-14T01:56:41.458079+00:00 app[web.1]: at RequestValidator.validate (/app/node_modules/express-openapi-validator/dist/middlewares/openapi.request.validator.js:51:41)
2021-01-14T01:56:41.458080+00:00 app[web.1]: at requestValidationHandler (/app/node_modules/express-openapi-validator/dist/index.js:144:79)
2021-01-14T01:56:41.458081+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
2021-01-14T01:56:41.458082+00:00 app[web.1]: at trim_prefix (/app/node_modules/express/lib/router/index.js:317:13)
2021-01-14T01:56:41.458083+00:00 app[web.1]: at /app/node_modules/express/lib/router/index.js:284:7
2021-01-14T01:56:41.458083+00:00 app[web.1]: at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)
2021-01-14T01:56:41.458084+00:00 app[web.1]: at next (/app/node_modules/express/lib/router/index.js:275:10)
2021-01-14T01:56:41.458084+00:00 app[web.1]: at /app/node_modules/express-openapi-validator/dist/middlewares/openapi.security.js:36:20
2021-01-14T01:56:41.458084+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
2021-01-14T01:56:41.458085+00:00 app[web.1]: at trim_prefix (/app/node_modules/express/lib/router/index.js:317:13)
2021-01-14T01:56:41.458085+00:00 app[web.1]: at /app/node_modules/express/lib/router/index.js:284:7
2021-01-14T01:56:41.458085+00:00 app[web.1]: at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)
2021-01-14T01:56:41.458086+00:00 app[web.1]: at next (/app/node_modules/express/lib/router/index.js:275:10)
2021-01-14T01:56:41.458086+00:00 app[web.1]: at /app/node_modules/express-openapi-validator/dist/middlewares/openapi.multipart.js:53:13
2021-01-14T01:56:41.458086+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
2021-01-14T01:56:41.461323+00:00 heroku[router]: at=info method=GET path="/liveness" host=leaderboardapi.herokuapp.com request_id=16016bde-c8e1-4ef0-a726-5cb06c64cd15 fwd="95.147.33.99" dyno=web.1 connect=1ms service=18ms status=400 bytes=416 protocol=https
To Reproduce Here’s my API definition that doesn’t throw up any errors
Actual behavior
I get a Bad Request: request should have required property 'headers'
error when trying to request GET /liveness
, which is a simple route that doesn’t require any headers or query strings. This works as expected locally, but doesn’t work when deployed on Heroku.
Expected behavior
I shouldn’t see the Bad Request: request should have required property 'headers'
error message, or I should be able to see a more useful error message.
Examples and context
Another detail I found was that my request seems to be going into the validateSecurity
handlers (I have a few logs in that middleware), but it ends abruptly with the Bad Request: request should have required property 'headers'
error.
Here’s my index.js file if it’s useful:
const express = require('express');
const cors = require('cors');
const path = require('path');
const { OpenApiValidator } = require('express-openapi-validator');
const config = require('./config');
const database = require('./lib/database')
const middleware = require('./middleware')
const app = express()
app.set('views', './src/views')
app.use(express.static('./public'))
app.engine('html', require('ejs').renderFile)
const apiSpec = path.join(__dirname, `../openapi/openapi.yml`)
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: false }));
(async function init() {
await database.connect();
await new OpenApiValidator({
apiSpec,
validateResponses: true,
operationHandlers: path.join(__dirname, './handlers'),
validateSecurity: {
handlers: {
verifyApiKey(req, scopes) {
return middleware.verifyApiKey(req)
},
bearerAuth(req, scopes) {
return middleware.verifyToken(req)
}
},
},
}).install(app)
app.use((err, _, res) => {
res.status(err.status || 500).json({
message: err.message,
errors: err.errors,
});
});
app.listen(config.port, () => console.log(`Listening on ${config.port}`))
})();
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:6 (3 by maintainers)
This problem occurred for Node 15 as well. I downgraded my Node.js to version 10 and the problem disappeared.
This happens because Express basically piggy-backs off the headers available on the standard Node HTTP message API. In Node v15.1.0,
message.headers
is now lazily computed using an accessor property on the prototype. Because of this, AJV cannot “see” that headers is actually set even though if you set your debugger to catch where the exception is thrown, you can readreq.headers
just fine (because it’s computed as you access it).This appears to have been patched in https://github.com/cdimascio/express-openapi-validator/pull/449 in 4.4.3. I would be happy to submit a similar patch for the 3.x branch if folks are still hesitant to upgrade to 4.x, but with so many goodies in 4.x, I’d say upgrade! 😂
See: https://nodejs.org/docs/latest-v16.x/api/http.html#messageheaders