withastro/astro · error · AstroError

RemoteImageNotAllowed

RemoteImageNotAllowed

Error message

Remote image ${imageURL} is not allowed by your image configuration.

What it means

When `inferSize: true` is set, `getImage()` must probe the remote image to learn its dimensions (packages/astro/src/assets/internal.ts:88-94). Before fetching, it checks the URL against the `images.domains` / `images.remotePatterns` allowlist; a remote `src` that is not allowed throws `RemoteImageNotAllowed` instead of making the request.

Solutions

  1. Add the host to `image.domains` in `astro.config.mjs` (or a matching `image.remotePatterns` entry) and restart dev.
  2. Alternatively supply explicit `width`/`height` and drop `inferSize`, which keeps the URL opaque without a probe.
  3. Check the exact hostname in the error message against your config — scheme, subdomain, and port must all line up with `remotePatterns`.

Example fix

// astro.config.mjs — before
image: { domains: [] }

// astro.config.mjs — after
image: { domains: ['cdn.example.com'] }
Defensive patterns

Strategy: validation

Validate before calling

// mirror Astro's allowlist check before calling getImage with inferSize
function isRemoteAllowed(src: string, domains: string[], remotePatterns: { hostname?: string }[]): boolean {
  const host = new URL(src).hostname;
  return domains.includes(host) || remotePatterns.some((p) => p.hostname === host);
}

if (opts.inferSize && !isRemoteAllowed(opts.src, image.domains, image.remotePatterns ?? [])) {
  throw new Error(`Domain not allowlisted for inferSize: ${opts.src}`);
}

Try / catch

try {
  const img = await getImage({ src: url, inferSize: true });
} catch (err) {
  if (err.name === 'RemoteImageNotAllowed') {
    // fall back to explicitly sized transform, or prompt the user to allowlist the domain
  } else throw err;
}

Prevention

When it happens

Trigger: `getImage({ src: 'https://cdn.example.com/hero.png', inferSize: true })` while `cdn.example.com` is absent from `image.domains` and matches no `image.remotePatterns` entry.

Common situations: Enabling `inferSize` for existing remote images without updating the image security config; new CDNs or subdomains after a migration; typos in the domain config (`www.` vs bare domain).

Related errors


AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18). Data as JSON: /api/errors/714b585c804201f4. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/assets/internal.ts:92

	const service = await getConfiguredImageService();

	// If the user inlined an import, something fairly common especially in MDX, or passed a function that returns an Image, await it for them
	const resolvedOptions: ImageTransform = {
		...options,
		src: await resolveSrc(options.src),
	};

	let originalWidth: number | undefined;
	let originalHeight: number | undefined;

	// Infer size for remote images if inferSize is true
	if (resolvedOptions.inferSize) {
		delete resolvedOptions.inferSize; // Delete so it doesn't end up in the attributes

		if (isRemoteImage(resolvedOptions.src) && isRemotePath(resolvedOptions.src)) {
			if (!isRemoteAllowed(resolvedOptions.src, imageConfig)) {
				throw new AstroError({
					...AstroErrorData.RemoteImageNotAllowed,
					message: AstroErrorData.RemoteImageNotAllowed.message(resolvedOptions.src),
				});
			}

			const getRemoteSize = (url: string) =>
				service.getRemoteSize?.(url, imageConfig, logger) ?? inferRemoteSize(url, imageConfig);
			const result = await getRemoteSize(resolvedOptions.src); // Directly probe the image URL
			resolvedOptions.width ??= result.width;
			resolvedOptions.height ??= result.height;
			// We've already paid for the fetch; reuse it to pin down the output format so the URL
			// (and any baked filename) doesn't have to defer or refetch.
			if (result.format) {
				resolvedOptions.format ??= resolveDefaultOutputFormat(result.format);
			}
			originalWidth = result.width;
			originalHeight = result.height;
		}

View on GitHub (pinned to e294953aa8)