vercel/next.js · error

Specified images.remotePatterns must have protocol "http" or

Error message

Specified images.remotePatterns must have protocol "http" or "https" received "${proto}".

What it means

Each entry in `images.remotePatterns` may have `protocol` set to 'http', 'https', or omitted (undefined). The normalizer at config.ts:706-713 strips a trailing ':' then rejects any other value, because `new URL()` would accept arbitrary schemes (ftp:, file:, data:) that the image optimizer must not proxy. This is a security boundary check.

Source

Thrown at packages/next/src/server/config.ts:710

        },
      ]
    }

    if (images.remotePatterns) {
      if (!Array.isArray(images.remotePatterns)) {
        throw new Error(
          `Specified images.remotePatterns should be an Array received ${typeof images.remotePatterns}.\nSee more info here: https://nextjs.org/docs/messages/invalid-images-config`
        )
      }

      // We must convert URL to RemotePattern since URL has a colon in the protocol
      // and also has additional properties we want to filter out. Also, new URL()
      // accepts any protocol so we need manual validation here.
      images.remotePatterns = images.remotePatterns.map(
        ({ protocol, hostname, port, pathname, search }) => {
          const proto = protocol?.replace(/:$/, '')
          if (!['http', 'https', undefined].includes(proto)) {
            throw new Error(
              `Specified images.remotePatterns must have protocol "http" or "https" received "${proto}".`
            )
          }
          return {
            protocol: proto as 'http' | 'https' | undefined,
            hostname,
            port,
            pathname,
            search,
          }
        }
      )

      // static images are automatically prefixed with assetPrefix
      // so we need to ensure _next/image allows downloading from
      // this resource
      if (config.assetPrefix?.startsWith('http')) {
        try {

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Set protocol to 'https' (preferred) or 'http': `{ protocol: 'https', hostname: 'cdn.example.com' }`.
  2. Omit protocol entirely if the default ('https' behavior) is acceptable.
  3. Double-check there is no trailing colon: use `'https'` not `'https:'`.

Example fix

// before
module.exports = { images: { remotePatterns: [{ protocol: 'ftp', hostname: 'cdn.example.com' }] } }
// after
module.exports = { images: { remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }] } }
Defensive patterns

Strategy: validation

Validate before calling

const allowed = ['http', 'https', undefined];
for (const p of config.images?.remotePatterns ?? []) {
  const proto = (p.protocol ?? '').replace(/:$/, '');
  if (proto !== '' && !['http', 'https'].includes(proto)) throw new Error('invalid protocol: ' + proto);
}

Type guard

function isValidProtocol(p: unknown): p is 'http' | 'https' | undefined {
  return p === undefined || p === 'http' || p === 'https' || p === 'http:' || p === 'https:';
}

Prevention

When it happens

Trigger: Supplying `protocol: 'ftp'`, `protocol: 'file'`, `protocol: 'data'`, or a malformed value like `protocol: 'http//'` in a remotePattern.

Common situations: Copy-pasting a URL scheme from an asset link that isn't HTTP(S). Using an older config that allowed looser values. Typos such as `protcol` leaving protocol derived from another source.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/af1839cda3c5f91e. Report an issue: GitHub.