vitejs/vite · error · Error
Cannot import non-asset file
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
importAnalysis rejects bare imports of files that live in the /public directory. Public files are served/copied verbatim and are not module-graph entries, so importing them as JS/CSS would break the build. The guard checks specifiers starting with '/' that resolve via checkPublicFile and are not assets (assetsInclude) or already ?url-qualified.
Solutions
- Move the file out of /public into src (or another source dir) so it becomes a normal module.
- If you only need the URL, import with the ?url suffix: `import url from '/file.js?url'` (the message suggests injectQuery(specifier, 'url')).
- Reference public JS/CSS via <script src>/<link href> in index.html instead of importing them.
- If the file is genuinely an asset, ensure config.assetsInclude matches its extension so the guard treats it as an asset.
Example fix
// before import data from '/config.json' // after — move config.json to src/, then import data from './config.json' // or just get the URL import dataUrl from '/config.json?url'
Defensive patterns
Strategy: validation
Validate before calling
// Lint source for imports that resolve into /public
import { checkPublicFile } from 'vite'
function isPublicImport(specifier, config) {
return specifier[0] === '/' && checkPublicFile(specifier, config)
&& !config.assetsInclude(specifier) && !specifier.includes('?url')
}
if (isPublicImport(specifier, config)) throw new Error('Use ?url or move out of /public') Type guard
function isPublicNonAsset(specifier, config): boolean {
return specifier.startsWith('/')
&& checkPublicFile(specifier, config) !== undefined
&& !config.assetsInclude(specifier.replace(/\?.*$/, ''))
&& !/\?url$/.test(specifier)
} Prevention
- Keep importable modules under src; reserve /public for verbatim assets only.
- Reference public JS/CSS via HTML tags, not import statements.
- Use the ?url suffix when you need a public file's URL in JS.
When it happens
Trigger: Code does `import x from '/data.json'` or `import './public/script.js'`-style references where the target is actually in the public dir. The check fires when specifier starts with '/', resolves to a public file, and is not classed as an asset or marked with ?url.
Common situations: Developers putting shared runtime JS/JSON in /public intending to import it, or moving a file into /public without updating imports. Also triggered by absolute '/...' imports that coincidentally match a public filename.
Related errors
- " } is not supported for assets in files
- ?url is not supported with CSS modules.
- [vite] The requested module
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/a68f57a6541a8d91.
Report an issue: GitHub.
Appendix: 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 b4d66fee14)