webpack/webpack · error · Error

${nextUrl.href} doesn't match the allowedUris policy after r

Error message

${nextUrl.href} doesn't match the allowedUris policy after redirect. These URIs are allowed:
${allowedUris.map((uri) => ` - ${uri}`).join("\n")}

What it means

After a redirect resolves to a valid http/https URL, validateRedirectLocation runs `isAllowed(nextUrl.href)` and rejects if the new URL does not match the configured `allowedUris` policy (lib/schemes/HttpUriPlugin.js:766, isAllowed at :1059). Unlike the initial-request check, this catches hosts reachable only through a redirect chain.

Source

Thrown at lib/schemes/HttpUriPlugin.js:767

					 */
					const validateRedirectLocation = (location, base) => {
						/** @type {URL} */
						let nextUrl;
						try {
							nextUrl = new URL(location, base);
						} catch (err) {
							throw new Error(
								`Invalid redirect URL: ${sanitizeUrlForError(location)}`,
								{ cause: err }
							);
						}
						if (nextUrl.protocol !== "http:" && nextUrl.protocol !== "https:") {
							throw new Error(
								`Redirected URL uses disallowed protocol: ${sanitizeUrlForError(nextUrl.href)}`
							);
						}
						if (!isAllowed(nextUrl.href)) {
							throw new Error(
								`${nextUrl.href} doesn't match the allowedUris policy after redirect. These URIs are allowed:\n${allowedUris
									.map((uri) => ` - ${uri}`)
									.join("\n")}`
							);
						}
						return nextUrl.href;
					};
					/**
					 * Processes the provided url.
					 * @param {string} url URL
					 * @param {string | null} integrity integrity
					 * @param {(err: Error | null, resolveContentResult?: ResolveContentResult) => void} callback callback
					 * @param {number=} redirectCount number of followed redirects
					 */
					const resolveContent = (
						url,
						integrity,
						callback,

View on GitHub (pinned to 318421ea8a)

Solutions

  1. Add the redirect target host to `experiments.buildHttp.allowedUris` (e.g. the S3 / backend CDN host).
  2. Use a RegExp or function allow-list entry to cover signed-URL hosts whose paths vary.
  3. Pin the final resolved URL in the lockfile so the redirect is not followed on subsequent builds.
  4. Confirm the redirect target is genuinely trusted before widening the policy (it is a security boundary).

Example fix

// before
experiments: { buildHttp: { allowedUris: ['https://registry.example.com/'] } }
// registry 302s to https://objects.example.com/pkg.tgz -> error

// after
experiments: {
  buildHttp: {
    allowedUris: [
      'https://registry.example.com/',
      'https://objects.example.com/'
    ]
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate allowedUris covers known redirect targets before building
function assertAllowedCoversRedirect(allowed, fromUrl, toUrl) {
  const ok = allowed.some((a) => {
    if (typeof a === 'string') return toUrl.startsWith(new URL(a).href);
    if (typeof a === 'function') return a(toUrl);
    return a.test(toUrl);
  });
  if (!ok) throw new Error(`allowedUris missing redirect target ${toUrl} (from ${fromUrl})`);
}

Try / catch

compiler.hooks.failed.tap('AllowedUrisGuard', (err) => {
  if (/allowedUris policy after redirect/.test(err.message)) {
    console.error('Add the redirect target host to experiments.buildHttp.allowedUris');
  }
});

Prevention

When it happens

Trigger: `experiments.buildHttp.allowedUris` lists `https://cdn.a.com/` but the requested module on `cdn.a.com` 302s to `https://cdn.b.com/...`. Each allowed entry can be a string prefix, a RegExp, or a function; none match the redirect target.

Common situations: CDN front-door redirects to a different backend domain not in allowedUris; a package host redirects to a signed S3 URL on a different bucket host; default allowedUris too narrow; forgot to register a mirror domain.

Related errors


AI-assisted analysis of webpack/webpack@318421ea8a (2026-08-03). Data as JSON: /data/errors/6fd45ea25985fa34.json. Report an issue: GitHub.