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
- Move the file out of `public` into `src` (or elsewhere) and import it normally.
- If you only need its URL, append `?url`: `import dataUrl from '/data.js?url'`.
- Reference public files via HTML `<script src="/data.js">` / `<link href="/style.css">` instead of importing.
- 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
- Keep JS/CSS/JSON modules in `src`, not `public`.
- Reference `public` files only via HTML attributes or runtime `fetch`.
- Use the `?url` suffix when you need a public file's URL from JS.
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
- { runtime: "${result.runtime}" } is not supported for assets
- `renderLegacyChunks` and `renderModernChunks` cannot be both
- @vitejs/plugin-legacy does not support library mode.
- HMR is not supported by this runner transport, but `hmr` opt
- Invalid environment name "${name}". Environment names must o
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/a68f57a6541a8d91.json.
Report an issue: GitHub.