expressjs/express · warning
Url must be a string
Error message
Url must be a string
What it means
A deprecation warning (via `deprecate()`, not a throw) from `res.redirect` when the url argument is truthy but not a string (number, object, URL instance, array). The value is then passed to `res.location` → `encodeUrl`, which coerces it to a string, often producing a nonsensical Location header like `[object Object]`; a future major version will reject non-strings outright.
Source
Thrown at lib/response.js:831
*/
res.redirect = function redirect(url) {
var address = url;
var body;
var status = 302;
// allow status / url
if (arguments.length === 2) {
status = arguments[0]
address = arguments[1]
}
if (!address) {
deprecate('Provide a url argument');
}
if (typeof address !== 'string') {
deprecate('Url must be a string');
}
if (typeof status !== 'number') {
deprecate('Status must be a number');
}
// Set location header
address = this.location(address).get('Location');
// Support text/{plain,html} by default
this.format({
text: function(){
body = statuses.message[status] + '. Redirecting to ' + address
},
html: function(){
var u = escapeHtml(address);
body = '<!DOCTYPE html><head><title>' + statuses.message[status] + '</title></head>'View on GitHub ↗ (pinned to a3714473fe)
Solutions
- Convert to a string before redirecting: `res.redirect(url.href)` or `res.redirect(String(target))` when the value is a URL object.
- Check the two-argument form's order: `res.redirect(status, url)` — status first, url second.
- Validate request-derived targets are strings (repeat query params become arrays) and reject otherwise.
Example fix
// before
const target = new URL('/dashboard', baseUrl);
res.redirect(target);
// after
const target = new URL('/dashboard', baseUrl);
res.redirect(target.href); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof target !== 'string') {
return res.status(400).send('Bad redirect target');
}
res.redirect(target); Type guard
function isUrlString(u) {
return typeof u === 'string' && u.length > 0;
} Prevention
- Query params can arrive as arrays — typeof-check redirect targets sourced from req.query
- Validate redirect targets against an allowlist of hosts/paths anyway (open-redirect defense), which naturally enforces string type
- Convert non-string values explicitly and deliberately, never rely on implicit coercion
When it happens
Trigger: `res.redirect(new URL('https://example.com'))`, `res.redirect({ path: '/home' })`, `res.redirect(301)` when the second (url) argument was forgotten so the number is treated as the url, or an array-valued query param used as the target.
Common situations: Passing WHATWG URL objects without calling `.toString()`/`.href`; swapped argument order in the two-argument form; redirect targets from JSON config or req.query arriving as objects/arrays.
Related errors
- Provide a url argument
- Status must be a number
- path must be a string to res.sendFile
- Content-Type cannot be set to an Array
- name argument is required to req.get
AI-assisted analysis of expressjs/express@a3714473fe (2026-07-31).
Data as JSON: /data/errors/e442601b34ccddd3.json.
Report an issue: GitHub ↗.