vercel/next.js · error

Specified images.loader property (${images.loader}) cannot b

Error message

Specified images.loader property (${images.loader}) cannot be used with images.loaderFile property. Please set images.loader to "custom".

What it means

`images.loaderFile` is only valid with `loader: 'default'` (where the file overrides the default) or `loader: 'custom'` (fully custom loader). The check at config.ts:789-794 throws when loaderFile is set but loader is a built-in named loader like 'cloudinary', because mixing a built-in loader with a custom file is contradictory and the framework cannot decide which to use.

Source

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

      images.path === imageConfigDefault.path &&
      result.basePath &&
      !pathHasPrefix(images.path, result.basePath)
    ) {
      images.path = `${result.basePath}${images.path}`
    }

    // Append trailing slash for non-default loaders and when trailingSlash is set
    if (
      images.path &&
      !images.path.endsWith('/') &&
      (images.loader !== 'default' || result.trailingSlash)
    ) {
      images.path += '/'
    }

    if (images.loaderFile) {
      if (images.loader !== 'default' && images.loader !== 'custom') {
        throw new Error(
          `Specified images.loader property (${images.loader}) cannot be used with images.loaderFile property. Please set images.loader to "custom".`
        )
      }
      const absolutePath = join(dir, images.loaderFile)
      if (!existsSync(absolutePath)) {
        throw new Error(
          `Specified images.loaderFile does not exist at "${absolutePath}".`
        )
      }
      images.loaderFile = absolutePath
    }
  }

  warnCustomizedOption(
    result,
    'experimental.esmExternals',
    true,
    'experimental.esmExternals is not recommended to be modified as it may disrupt module resolution',

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Set `loader: 'custom'` when supplying `loaderFile`: `images: { loader: 'custom', loaderFile: './loaders/my-loader.ts' }`.
  2. Or remove `loaderFile` if you want to keep the built-in named loader.
  3. Confirm the loaderFile exports a default function with the `({ src, width, quality }) => string` signature.

Example fix

// before
module.exports = { images: { loader: 'cloudinary', loaderFile: './my-loader.js' } }
// after
module.exports = { images: { loader: 'custom', loaderFile: './my-loader.js' } }
Defensive patterns

Strategy: validation

Validate before calling

const { loader, loaderFile } = config.images ?? {};
if (loaderFile && loader && loader !== 'default' && loader !== 'custom') {
  throw new Error('set images.loader to "custom" when using loaderFile');
}

Type guard

function loaderFileCompatible(images: any): boolean {
  return !images?.loaderFile || images?.loader === 'default' || images?.loader === 'custom' || !images?.loader;
}

Prevention

When it happens

Trigger: Setting both `images: { loader: 'cloudinary', loaderFile: './my-loader.js' }`. The named loader would override the file, so the combination is rejected.

Common situations: Starting from a named loader config and adding a loaderFile to tweak behavior, instead of switching loader to 'custom'. Copying loaderFile from an example while leaving a previous loader value.

Related errors


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