{"id":"32077ce51e2c037d","repo":"expressjs/express","slug":"not-acceptable","errorCode":null,"errorMessage":"Not Acceptable","messagePattern":"Not Acceptable","errorType":"http","errorClass":"HttpError","httpStatus":406,"severity":"warning","filePath":"lib/response.js","lineNumber":590,"sourceCode":"  var req = this.req;\n  var next = req.next;\n\n  var keys = Object.keys(obj)\n    .filter(function (v) { return v !== 'default' })\n\n  var key = keys.length > 0\n    ? req.accepts(keys)\n    : false;\n\n  this.vary(\"Accept\");\n\n  if (key) {\n    this.set('Content-Type', normalizeType(key).value);\n    obj[key](req, this, next);\n  } else if (obj.default) {\n    obj.default(req, this, next)\n  } else {\n    next(createError(406, {\n      types: normalizeTypes(keys).map(function (o) { return o.value })\n    }))\n  }\n\n  return this;\n};\n\n/**\n * Set _Content-Disposition_ header to _attachment_ with optional `filename`.\n *\n * @param {String} filename\n * @return {ServerResponse}\n * @public\n */\n\nres.attachment = function attachment(filename) {\n  const name = filename !== undefined ? basename(filename) : undefined;\n  if (name) {","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/expressjs/express/blob/a3714473feb3d2908add734d340e7755fd85e0a3/lib/response.js#L572-L608","documentation":"Not thrown directly — `res.format(obj)` calls `next(createError(406, {...}))` when the request's Accept header matches none of the content types offered in the object and no `default` handler is provided. \"Not Acceptable\" is the standard HTTP 406 reason phrase; the error carries a `types` property listing the types the server could have produced.","triggerScenarios":"A client sends `Accept: application/xml` (or any type not among the keys passed to `res.format`) to a route using `res.format({ json: ..., html: ... })` with no `default` key; API clients sending overly strict Accept headers.","commonSituations":"Strict API clients or security scanners sending unusual Accept headers; curl/tests specifying an unsupported Accept value; content-negotiation routes that forgot a default branch, turning benign clients into 406 responses.","solutions":["Add a `default` callback to the res.format object so unmatched Accept headers get a sensible fallback instead of a 406.","Handle the 406 in your error middleware (the error has status 406 and a `types` array) to return a clean message.","If negotiation isn't really needed, drop res.format and always send one type."],"exampleFix":"// before\nres.format({ json: () => res.json(data), html: () => res.render('page', data) });\n// after\nres.format({ json: () => res.json(data), html: () => res.render('page', data), default: () => res.status(406).json({ error: 'Not Acceptable', accepts: ['application/json', 'text/html'] }) });","handlingStrategy":"fallback","validationCode":"res.format({\n  json() { res.json(payload); },\n  html() { res.render('view', payload); },\n  default() { res.status(406).send('Not Acceptable'); }\n});","typeGuard":null,"tryCatchPattern":"app.use((err, req, res, next) => {\n  if (err.status === 406) {\n    return res.status(406).json({ error: 'no acceptable representation' });\n  }\n  next(err);\n});","preventionTips":["Always provide a default handler in res.format — without it, an unmatched Accept header raises this 406 error","Handle the 406 in your error middleware so clients get a clean response instead of a stack trace","Test routes with Accept: application/xml or other types you don't serve"],"tags":["express","content-negotiation","http-406","accept-header"],"analyzedSha":"a3714473feb3d2908add734d340e7755fd85e0a3","analyzedAt":"2026-07-31T18:55:36.968Z","schemaVersion":2}