{"record":{"id":"0f003aa98ba5977c","repo":"denoland/deno","slug":"invalid-redirect-status-code-status","errorCode":null,"errorMessage":"Invalid redirect status code: ${status}","messagePattern":"Invalid redirect status code: (.+?)","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/23_response.js","lineNumber":680,"sourceCode":"    initializeResponseBase(response, inner, \"immutable\");\n    maybeSetServeNativeFromInner(response);\n    return response;\n  }\n\n  /**\n   * @param {string} url\n   * @param {number} status\n   * @returns {Response}\n   */\n  static redirect(url, status = 302) {\n    const prefix = \"Failed to execute 'Response.redirect'\";\n    url = webidlConvertersUSVString(url, prefix, \"Argument 1\");\n    status = webidlConvertersUnsignedShort(status, prefix, \"Argument 2\");\n\n    const baseURL = getLocationHref();\n    const parsedURL = new URL(url, baseURL);\n    if (!redirectStatus(status)) {\n      throw new RangeError(`Invalid redirect status code: ${status}`);\n    }\n    const inner = newInnerResponse(status);\n    inner.type = \"default\";\n    ArrayPrototypePush(inner.headerList, [\"Location\", parsedURL.href]);\n    const response = webidl.createBranded(Response);\n    initializeResponseBase(response, inner, \"immutable\");\n    maybeSetServeNativeFromInner(response);\n    return response;\n  }\n\n  /**\n   * @param {any} data\n   * @param {ResponseInit} init\n   * @returns {Response}\n   */\n  static json(data = undefined, init = undefined) {\n    const prefix = \"Failed to execute 'Response.json'\";\n    data = webidlConvertersAny(data);","sourceCodeStart":662,"sourceCodeEnd":698,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/fetch/23_response.js#L662-L698","documentation":"Response.redirect(url, status = 302) parses the URL, then requires redirectStatus(status) — true only for 301, 302, 303, 307, and 308. Any other value (including other 3xx codes like 300, 304, 306, or non-3xx values) throws RangeError 'Invalid redirect status code: <status>'.","triggerScenarios":"Response.redirect('/login', 3021), Response.redirect(url, 304), or a status read from a config map that used a redirect-status placeholder like 0/undefined after failed lookup.","commonSituations":"Config-driven redirects where the code came from user input or a CMS; forwarding an upstream status verbatim into Response.redirect (upstream 304/300 then fails); typos like 3088.","solutions":["Use one of 301, 302, 303, 307, 308 — prefer 302/308 for temporary/permanent generic redirects","Validate status against a Set([301,302,303,307,308]) before calling Response.redirect, defaulting to 302","When forwarding upstream responses, use `new Response(upstream.body, upstream)` instead of Response.redirect if the status may be non-redirect"],"exampleFix":"// before\nreturn Response.redirect(nextUrl, upstreamStatus); // 300/304 throw\n\n// after\nconst REDIRECTS = new Set([301, 302, 303, 307, 308]);\nconst status = REDIRECTS.has(upstreamStatus) ? upstreamStatus : 302;\nreturn Response.redirect(nextUrl, status);","handlingStrategy":"type-guard","validationCode":"const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\nfunction redirect(url, status) {\n  return Response.redirect(url, REDIRECT_STATUSES.has(status) ? status : 302);\n}","typeGuard":"/** @param {unknown} s */\nfunction isValidRedirectStatus(s) {\n  return [301, 302, 303, 307, 308].includes(Number(s));\n}","tryCatchPattern":null,"preventionTips":["Restrict redirect statuses to 301/302/303/307/308 via a Set lookup with a 302 default","Never forward upstream statuses blindly into Response.redirect","For non-redirect upstream statuses, pass the Response through instead of rebuilding it"],"tags":["fetch","response","redirect","status-code"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}