vitejs/vite · error · Error
Package subpath ' ' is not defined by "exports" in .
Error message
Package subpath '${relativeId}' is not defined by "exports" in ${path.join(dir, 'package.json')}. What it means
During package resolution, Vite honors the 'exports' field of package.json. If the requested subpath does not match any exports entry (or exports is an array/non-object, treated as 'not exposed'), relativeId becomes undefined and Vite throws a Node-style ERR_PACKAGE_PATH_NOT_EXPORTED-style message naming the package.json path.
Solutions
- Import only the paths the package documents as exported (often just the package root).
- If you control the package, add the subpath to its 'exports' map.
- Check the package version against your assumption — a downgrade/upgrade may have changed exports.
- If a transitive dep is doing the bad import, update that dependency or open an issue upstream.
Example fix
// before
import _ from 'mylib/internal/util'
// after — use an exported path
import _ from 'mylib'
// or, if you own mylib, in package.json:
{ "exports": { ".": "./dist/index.js", "./internal/util": "./dist/internal/util.js" } } Defensive patterns
Strategy: validation
Validate before calling
// Verify a subpath is exported before importing
import { resolveExports } from 'resolve.exports'
function assertExported(pkgJsonPath, subpath, conditions) {
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
const resolved = resolveExports(pkg, subpath, { conditions })
if (!resolved) throw new Error(`${subpath} is not exported by ${pkgJsonPath}`)
} Type guard
function isExportedSubpath(pkg, subpath): boolean {
const exp = pkg.exports
if (!exp || typeof exp !== 'object' || Array.isArray(exp)) return false
return subpath in exp || '.' in exp // simplified
} Try / catch
try {
return await import('pkg/subpath')
} catch (e) {
if (/not defined by "exports"/.test(e.message)) {
return await import('pkg') // fall back to root export
}
throw e
} Prevention
- Prefer root imports over deep imports unless documented.
- When upgrading a dependency, diff its exports map.
- If you own the package, expose the subpaths your consumers need.
When it happens
Trigger: Importing 'pkg/somesubpath' where pkg's package.json has an 'exports' map that does not list that subpath. The throw happens in resolvePackageImports when splitFileAndPostfix + resolveExportsOrImports returns undefined.
Common situations: Deep imports the package author did not export (e.g. 'lodash/fp/internal'), version upgrades that tightened the exports map, or a typo in the subpath. Also seen when a package switches from CommonJS (no exports) to ESM-with-exports and previously-working deep imports break.
Related errors
- Failed to resolve . This package is ESM only but it was…
- config must export or return an object.
- import.meta.resolve is not supported in CJS config files
- Name in package.json is required if option…
- [vite] Named export ' ' not found. The requested module ' '…
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/9d2e64769ea941e4.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/plugins/resolve.ts:1081
const { file, postfix } = splitFileAndPostfix(relativeId)
const exportsId = resolveExportsOrImports(
data,
file,
options,
'exports',
externalize,
)
if (exportsId !== undefined) {
relativeId = exportsId + postfix
} else {
relativeId = undefined
}
} else {
// not exposed
relativeId = undefined
}
if (!relativeId) {
throw new Error(
`Package subpath '${relativeId}' is not defined by "exports" in ` +
`${path.join(dir, 'package.json')}.`,
)
}
} else if (options.mainFields.includes('browser') && isObject(browserField)) {
// resolve without postfix (see #7098)
const { file, postfix } = splitFileAndPostfix(relativeId)
const mapped = mapWithBrowserField(file, browserField)
if (mapped) {
relativeId = mapped + postfix
} else if (mapped === false) {
setResolvedCache(id, browserExternalId, options)
return browserExternalId
}
}
if (relativeId) {
const resolved = tryFsResolve(View on GitHub (pinned to b4d66fee14)