res.set('Content-Type') silently sets header to literal string 'false' for unknown types · Issue #7034 · expressjs/express · GitHub
Skip to content

res.set('Content-Type') silently sets header to literal string 'false' for unknown types #7034

Description

@veeceey

When calling res.set('Content-Type', value) where the value doesn't contain a / (like a bare extension or shorthand), mime.contentType(value) is used to resolve the full MIME type. However, if mime.contentType() returns false (for unrecognized types), the Content-Type header is set to the literal string "false" instead of keeping the original value.

Reproduction:

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.set('Content-Type', 'some-custom-type');
  res.send('hello');
});

app.listen(3000);

Requesting / returns Content-Type: false in the response headers.

Root cause:

In res.set() (response.js), the Content-Type branch does:

if (field.toLowerCase() === 'content-type') {
  if (Array.isArray(value)) {
    throw new TypeError('Content-Type cannot be set to an Array');
  }
  value = mime.contentType(value)  // can return false!
}
this.setHeader(field, value);

When mime.contentType(value) returns false, the value false is passed to setHeader, which coerces it to the string "false".

Contrast with res.type() which handles this correctly:

var ct = type.indexOf('/') === -1
  ? (mime.contentType(type) || 'application/octet-stream')
  : type;

Expected behavior:

When mime.contentType() returns false, res.set should fall back to the original string value rather than setting the header to "false".

Activity

  1. added a commit that references this issue on Feb 14, 2026
    a00eb83
  2. krzysdz commented on Feb 14, 2026

    @krzysdz
    Contributor

    mime.contentType() returns false only if the provided argument is not a valid mime type or a known file extension (list is in mime-db). The Content-Type header carries a media type, which MUST contain a "/" (see the linked RFC for exact definition).

    I think that maybe Express should throw an error if mime.contentType() returns false, so that this mistake is easier to catch.

  3. added a commit that references this issue on Feb 15, 2026
    329913c
  4. bjohansebas commented on Feb 15, 2026

    @bjohansebas
    Member

    That’s a good catch. Honestly, I’m not sure what we should do here yet. I don’t really like the idea of throwing an error in this case (even though it seems logical).

    What I do think we should do is document it. I have it on my TODO list to add it to the new page.

  5. added a commit that references this issue on Feb 15, 2026
    0d3809c
  6. added a commit that references this issue on Feb 18, 2026
    f7777e7
  7. added a commit that references this issue on Feb 25, 2026
    e49decf
  8. mahmoodhamdi commented on Mar 15, 2026

    @mahmoodhamdi

    The issue is in this path: res.set() -> mime.contentType() -> returns false -> header set to literal "false".

    Looking at the code in lib/response.js, the contentType method calls mime.contentType() and sets whatever it returns without checking for false:

    res.set('Content-Type', type);
    // where type could be the literal string "false"

    A simple guard would fix this:

    const ct = mime.contentType(type);
    if (ct) {
      this.set('Content-Type', ct);
    }

    The question is whether we should silently ignore unrecognized types, warn, or throw. Silently ignoring could hide bugs. Maybe logging a warning and keeping the original value would be the safest approach:

    const ct = mime.contentType(type);
    if (ct) {
      this.set('Content-Type', ct);
    } else {
      // Unrecognized shorthand, use the original value as-is
      this.setHeader('Content-Type', type);
    }
  9. JiwaniZakir commented on Mar 17, 2026

    @JiwaniZakir

    I think I see what's going on here. Going to put together a fix.

  10. added a commit that references this issue on Mar 25, 2026
    7175b46
  11. blakeembrey commented on Mar 31, 2026

    @blakeembrey
    Member

    After a brief review I'm of the opinion that this should error. It currently doesn't work, and some downstream code relies on Content-Type being valid (just

    express/lib/utils.js

    Lines 225 to 238 in e509919

    ). If it's set to something invalid, it creates a harder to debug experience later. By throwing an error, you'll at least have a stack track to follow and fix.

    Currently the behavior doesn't work at all, since it sets to false. So there shouldn't be anyone relying on this behavior successfully, but if there is changing it to a different header will also create surprises. IMO it's better to have a clear upgrade path for them.

    Finally, I also advocate for adding a deprecation message to the behavior altogether, and removing in v6. We already have a clearer method, res.type, that can be used for this and IMO .set('content-type', 'x') being changed underneath you is a surprising behavior of the library.

  12. added a commit that references this issue on Apr 1, 2026
    c24200c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions