{"id":"e442601b34ccddd3","repo":"expressjs/express","slug":"url-must-be-a-string","errorCode":null,"errorMessage":"Url must be a string","messagePattern":"Url must be a string","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"lib/response.js","lineNumber":831,"sourceCode":" */\n\nres.redirect = function redirect(url) {\n  var address = url;\n  var body;\n  var status = 302;\n\n  // allow status / url\n  if (arguments.length === 2) {\n    status = arguments[0]\n    address = arguments[1]\n  }\n\n  if (!address) {\n    deprecate('Provide a url argument');\n  }\n\n  if (typeof address !== 'string') {\n    deprecate('Url must be a string');\n  }\n\n  if (typeof status !== 'number') {\n    deprecate('Status must be a number');\n  }\n\n  // Set location header\n  address = this.location(address).get('Location');\n\n  // Support text/{plain,html} by default\n  this.format({\n    text: function(){\n      body = statuses.message[status] + '. Redirecting to ' + address\n    },\n\n    html: function(){\n      var u = escapeHtml(address);\n      body = '<!DOCTYPE html><head><title>' + statuses.message[status] + '</title></head>'","sourceCodeStart":813,"sourceCodeEnd":849,"githubUrl":"https://github.com/expressjs/express/blob/a3714473feb3d2908add734d340e7755fd85e0a3/lib/response.js#L813-L849","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst target = new URL('/dashboard', baseUrl);\nres.redirect(target);\n// after\nconst target = new URL('/dashboard', baseUrl);\nres.redirect(target.href);","handlingStrategy":"type-guard","validationCode":"if (typeof target !== 'string') {\n  return res.status(400).send('Bad redirect target');\n}\nres.redirect(target);","typeGuard":"function isUrlString(u) {\n  return typeof u === 'string' && u.length > 0;\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["express","redirect","deprecation","type-error"],"analyzedSha":"a3714473feb3d2908add734d340e7755fd85e0a3","analyzedAt":"2026-07-31T18:55:36.968Z","schemaVersion":2}