{"id":"9d2e64769ea941e4","repo":"vitejs/vite","slug":"package-subpath-relativeid-is-not-defined-by","errorCode":null,"errorMessage":"Package subpath '${relativeId}' is not defined by \"exports\" in ${path.join(dir, 'package.json')}.","messagePattern":"Package subpath '(.+?)' is not defined by \"exports\" in (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vite/src/node/plugins/resolve.ts","lineNumber":1081,"sourceCode":"      const { file, postfix } = splitFileAndPostfix(relativeId)\n      const exportsId = resolveExportsOrImports(\n        data,\n        file,\n        options,\n        'exports',\n        externalize,\n      )\n      if (exportsId !== undefined) {\n        relativeId = exportsId + postfix\n      } else {\n        relativeId = undefined\n      }\n    } else {\n      // not exposed\n      relativeId = undefined\n    }\n    if (!relativeId) {\n      throw new Error(\n        `Package subpath '${relativeId}' is not defined by \"exports\" in ` +\n          `${path.join(dir, 'package.json')}.`,\n      )\n    }\n  } else if (options.mainFields.includes('browser') && isObject(browserField)) {\n    // resolve without postfix (see #7098)\n    const { file, postfix } = splitFileAndPostfix(relativeId)\n    const mapped = mapWithBrowserField(file, browserField)\n    if (mapped) {\n      relativeId = mapped + postfix\n    } else if (mapped === false) {\n      setResolvedCache(id, browserExternalId, options)\n      return browserExternalId\n    }\n  }\n\n  if (relativeId) {\n    const resolved = tryFsResolve(","sourceCodeStart":1063,"sourceCodeEnd":1099,"githubUrl":"https://github.com/vitejs/vite/blob/89620f09afcfef6b35e7bb8660132ab5b4d0cd3b/packages/vite/src/node/plugins/resolve.ts#L1063-L1099","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nimport { escape } from 'lodash/escape'\n\n// after (lodash-es exposes only '.'; use the documented entry)\nimport { escape } from 'lodash-es'","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\n\nfunction subpathIsExported(pkgDir: string, subpath: string): boolean {\n  const pkg = JSON.parse(readFileSync(`${pkgDir}/package.json`, 'utf8'))\n  if (!pkg.exports) return true // no exports field => fs resolution applies\n  const keys = Object.keys(pkg.exports)\n  return keys.includes(subpath) || keys.includes('./' + subpath.replace(/^\\.?\\//, ''))\n}\n// before importing 'lib/internal/util':\nif (!subpathIsExported(require.resolve('lib').replace(/package\\.json$/, '..'), './internal/util')) {\n  throw new Error('refusing to import a subpath not in package exports')\n}","typeGuard":"function isExportedSubpath(exportsField: unknown, subpath: string): boolean {\n  if (!exportsField || typeof exportsField !== 'object') return true\n  return Object.prototype.hasOwnProperty.call(exportsField, subpath)\n}","tryCatchPattern":"try {\n  await import('lib/internal/util')\n} catch (e) {\n  if (/is not defined by \"exports\"/.test((e as Error).message)) {\n    // fall back to a documented entry point\n    return await import('lib')\n  }\n  throw e\n}","preventionTips":["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."],"tags":["resolve","exports","package-json","dependency"],"analyzedSha":"89620f09afcfef6b35e7bb8660132ab5b4d0cd3b","analyzedAt":"2026-08-03T19:28:02.920Z","schemaVersion":2}