withastro/astro · error · AstroError
RemoteImageNotAllowed
RemoteImageNotAllowed
Error message
Remote image ${imageURL} is not allowed by your image configuration. What it means
Thrown by getImage() when inferSize is set, the resolved src is a remote image string, and isRemoteAllowed(src, imageConfig) returns false. Astro requires remote image hosts to be explicitly allow-listed (image.domains / image.remotePatterns) before it will probe a remote URL for dimensions.
Source
Thrown at packages/astro/src/assets/internal.ts:90
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) ?? 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 d081033d5f)
Solutions
- Add the host to image.domains: image: { domains: ['other-host'] }.
- Or add a remotePatterns entry: image: { remotePatterns: [{ protocol: 'https', hostname: 'other-host' }] }.
- If the image is local, import it as an ESM asset instead of using a URL.
- Drop inferSize and supply explicit width/height to avoid the remote probe entirely.
Example fix
// astro.config.mjs
// before
image: { domains: ['cdn.example.com'] }
// after
image: { domains: ['cdn.example.com', 'other-host'] } Defensive patterns
Strategy: validation
Validate before calling
import { matchPattern } from 'astro/assets'; // pseudo
function isAllowedRemote(src: string, cfg: { domains?: string[]; remotePatterns?: any[] }): boolean {
const host = (() => { try { return new URL(src).hostname; } catch { return null; } })();
if (!host) return false;
return (cfg.domains ?? []).includes(host);
} Prevention
- Keep image.domains/remotePatterns in sync with every CDN you use.
- Prefer importing local assets over remote URLs where possible.
- When adding a new image host, update astro.config the same commit.
When it happens
Trigger: Calling getImage({ src: 'https://other-host/img.png', inferSize: true }) where 'other-host' is not in image.domains and does not match any image.remotePatterns. Only remote (string) paths that pass isRemotePath are checked against isRemoteAllowed.
Common situations: Author adds a new image CDN/hostname without updating astro.config image.domains or remotePatterns, switches from a local import to a remote URL, or copies an image URL from a third party.
Related errors
- UnsupportedImageFormat
- MissingImageDimension
- EnvPrefixConflictsWithSecret
- ServerOnlyModule
- CONTENT_TOO_LARGE
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/714b585c804201f4.
Report an issue: GitHub.