vitejs/vite · error · Error

Cannot import non-asset file ${specifier} which is inside /p

Error message

Cannot import non-asset file ${specifier} which is inside /public. JS/CSS files inside /public are copied as-is on build and can only be referenced via <script src> or <link href> in html. If you want to get the URL of that file, use ${injectQuery(specifier, 'url')} instead.

What it means

Thrown by import analysis when a JS/CSS import specifier resolves to a file inside the `/public` directory. Files in `public` are served/copied verbatim and are not processed as modules, so importing them as JS/CSS is disallowed; the message suggests using `?url` to get the file's URL instead.

Source

Thrown at packages/vite/src/node/plugins/importAnalysis.ts:578

              if (isBuiltin(environment.config.resolve.builtins, specifier)) {
                return
              }
            }
            // skip client
            if (specifier === clientPublicPath) {
              return
            }

            // warn imports to non-asset /public files
            if (
              specifier[0] === '/' &&
              !(
                config.assetsInclude(cleanUrl(specifier)) ||
                urlRE.test(specifier)
              ) &&
              checkPublicFile(specifier, config)
            ) {
              throw new Error(
                `Cannot import non-asset file ${specifier} which is inside /public. ` +
                  `JS/CSS files inside /public are copied as-is on build and ` +
                  `can only be referenced via <script src> or <link href> in html. ` +
                  `If you want to get the URL of that file, use ${injectQuery(
                    specifier,
                    'url',
                  )} instead.`,
              )
            }

            // normalize
            let [url, resolvedId] = await normalizeUrl(specifier, start)
            resolvedId = resolvedId || url

            // record as safe modules
            // safeModulesPath should not include the base prefix.
            // See https://github.com/vitejs/vite/issues/9438#issuecomment-1465270409
            config.safeModulePaths.add(fsPathFromUrl(stripBase(url, base)))

View on GitHub (pinned to 89620f09af)

Solutions

  1. Move the file out of `public` into `src` (or elsewhere) and import it normally.
  2. If you only need its URL, append `?url`: `import dataUrl from '/data.js?url'`.
  3. Reference public files via HTML `<script src="/data.js">` / `<link href="/style.css">` instead of importing.
  4. If the file is genuinely static data, fetch it at runtime via `fetch('/data.json')`.

Example fix

// before — file at public/data.js
import data from '/data.js';
// after — move to src/data.js
import data from './data.js';
// or, if you just need the URL
import dataUrl from '/data.js?url';
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs';
import path from 'node:path';

function assertNotPublicImport(specifier, publicDir) {
  if (specifier.startsWith('/') && existsSync(path.join(publicDir, specifier))) {
    throw new Error(`Do not import public file as a module: ${specifier}. Use ?url or move it to src.`);
  }
}
// assertNotPublicImport(specifier, config.publicDir);

Type guard

function isPublicImport(specifier, publicDir) {
  const { existsSync } = require('node:fs');
  const path = require('node:path');
  return specifier.startsWith('/') && existsSync(path.join(publicDir, specifier));
}

Prevention

When it happens

Trigger: A specifier starting with `/` that is not matched by `assetsInclude` or `?url`, but IS found by `checkPublicFile` (i.e. exists in `publicDir`) — e.g. `import data from '/data.js'` where `public/data.js` exists.

Common situations: Moving a JS/CSS/JSON file into `public/` (intending it as a static asset) but still importing it from source; importing a config/script that lives in `public`; misunderstanding that `public` files are for HTML `<script src>`/`<link href>` references, not ESM imports.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/a68f57a6541a8d91.json. Report an issue: GitHub.