vitejs/vite · error · Error
Package subpath '${relativeId}' is not defined by "exports"
Error message
Package subpath '${relativeId}' is not defined by "exports" in ${path.join(dir, 'package.json')}. What it means
Vite's resolver honors a package's package.json "exports" map (Node's subpath resolution). When a dependency declares an "exports" field but the deep-import path you requested matches none of its entries, Vite refuses to fall back to the filesystem and throws at packages/vite/src/node/plugins/resolve.ts:1081. This mirrors Node's own ERR_PACKAGE_PATH_NOT_EXPORTED so bundler and runtime resolution agree.
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 89620f09af)
Solutions
- Read the offending package's package.json exports field and import only a path that is actually listed (usually the bare package name or a documented subpath).
- If you control the package, add the subpath to its exports map (e.g. "./internal/util": "./src/internal/util.ts").
- Pin or downgrade the dependency to a version whose exports still allowed the deep import, if you cannot change the import.
- If you must bypass exports, alias the path in vite.config resolve.alias and resolve.conditions so Vite resolves the real file directly.
Example fix
// before
import { escape } from 'lodash/escape'
// after (lodash-es exposes only '.'; use the documented entry)
import { escape } from 'lodash-es' Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from 'node:fs'
import { createRequire } from 'node:module'
function subpathIsExported(pkgDir: string, subpath: string): boolean {
const pkg = JSON.parse(readFileSync(`${pkgDir}/package.json`, 'utf8'))
if (!pkg.exports) return true // no exports field => fs resolution applies
const keys = Object.keys(pkg.exports)
return keys.includes(subpath) || keys.includes('./' + subpath.replace(/^\.?\//, ''))
}
// before importing 'lib/internal/util':
if (!subpathIsExported(require.resolve('lib').replace(/package\.json$/, '..'), './internal/util')) {
throw new Error('refusing to import a subpath not in package exports')
} Type guard
function isExportedSubpath(exportsField: unknown, subpath: string): boolean {
if (!exportsField || typeof exportsField !== 'object') return true
return Object.prototype.hasOwnProperty.call(exportsField, subpath)
} Try / catch
try {
await import('lib/internal/util')
} catch (e) {
if (/is not defined by "exports"/.test((e as Error).message)) {
// fall back to a documented entry point
return await import('lib')
}
throw e
} Prevention
- Always import the bare package name or a subpath documented in the package's README/exports.
- Lock dependency versions and review the exports diff when upgrading.
- Run `node --conditions ... -e "console.log(require.resolve('lib/subpath'))"` in CI to assert deep imports resolve.
When it happens
Trigger: Importing a subpath that the package author did not expose, e.g. import x from 'lib/internal/util' when lib's package.json only exports '.' and './feature'. Also triggered by query/postfix-suffixed ids ('lib/dist/index.js?sourcemap') after splitFileAndPostfix fails to match, or by importing a path that only existed pre-exports (lib/package.json versions that added a restrictive exports field).
Common situations: Upgrading a dependency that introduced/ tightened its exports field (e.g. lodash-es, @vue/runtime-core, react-router); tooling (postcss, autoprefixer plugins) importing deep internal files; monorepo workspace packages whose exports forgot to list a subpath; using a build of a lib whose exports only point at ESM while you import CJS-only internals.
Related errors
- [vite]: Rolldown failed to resolve import "${exporter}" from
- Name in package.json is required if option "build.lib.fileNa
- failed to resolve rolldownOptions.input value: ${JSON.string
- Failed to load PostCSS config: ${e}
- Preprocessor dependency "${lang}" not found. Did you install
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/9d2e64769ea941e4.json.
Report an issue: GitHub.