vitejs/vite · error · Error
Could not resolve " " imported by " ". Is it installed?
Error message
Could not resolve "${peerDep}" imported by "${parentDep}". Is it installed? What it means
Injected at runtime by `vite:dep-optimizer`'s rolldown plugin into the pre-bundled module for an optional peer dependency that could not be resolved. When a dep declares an optional peer dep that is not installed, Vite externalizes it under a special namespace and emits code that throws this message in the browser when the module is actually imported. It is a lazy error: optimization succeeds, the failure surfaces only if the app imports that code path.
Solutions
- Install the missing peer: `npm install <peerDep>` (the message names both peerDep and parentDep).
- If the import is dead code, configure tree-shaking or dynamic-import it so the browser never loads it.
- Mark the peer as external (`build.rollupOptions.external`) if it is provided by the host environment at runtime.
- Update the parent dependency; newer versions may handle the optional peer more gracefully.
- If using a monorepo, ensure the peer is hoisted to where the parent dep resolves it.
Example fix
// before: @some-lib optionally peers on 'chart.js' which is uninstalled import Chart from '@some-lib/chart' // throws at runtime // after // $ npm install chart.js import Chart from '@some-lib/chart'
Defensive patterns
Strategy: try-catch
Validate before calling
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
function assertPeerInstalled(parentDep: string, peerDep: string) {
try {
const parentPkg = require.resolve(`${parentDep}/package.json`)
require.resolve(peerDep, { paths: [require('node:path').dirname(parentPkg)] })
} catch {
console.warn(`Optional peer '${peerDep}' of '${parentDep}' is missing; runtime import will throw.`)
}
} Try / catch
// in app code that may hit the externalized optional peer
try {
const mod = await import('@some-lib/optional-feature')
} catch (e) {
if (e instanceof Error && /Could not resolve ".*" imported by ".*"\. Is it installed\?/.test(e.message)) {
console.warn('Optional peer missing; falling back to default behavior.')
return null
}
throw e
} Prevention
- Install optional peer deps you actually use (the error names both peerDep and parentDep).
- Externalize peers provided by the host (build.rollupOptions.external) instead of letting the optimizer inject the throwing stub.
- Code-split optional features so the throwing module is never loaded when the peer is absent.
When it happens
Trigger: rolldownDepPlugin.ts:310 builds `module.exports = {}; throw new Error(...)` for ids under `optionalPeerDepNamespace` (format `...:peerDep:parentDep`). Triggered in the browser when app code imports a module that transitively imports an uninstalled optional peer dependency.
Common situations: A UI library (parent dep) optionally relies on a peer like `react`, `vue`, `@reduxjs/toolkit`, or a charting engine that is not installed. The package marks it `peerDependenciesMeta: { optional: true }`, so installers skip it, but the bundler still sees the import. Version mismatch where the peer is installed under a different name.
Related errors
- failed to resolve rolldownOptions.input value
- not implemented
- Failed to decode base64-encoded data URL, Buffer and atob…
- invalid rolldownOptions.input value.
- Not implemented
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/f4bbc469a85cc0a9.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/optimizer/rolldownDepPlugin.ts:310
key !== '__proto__' &&
key !== 'constructor' &&
key !== 'splice'
) {
console.warn(\`Module "${path}" has been externalized for browser compatibility. Cannot access "${path}.\${key}" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.\`)
}
}
}))`,
}
}
}
if (id.startsWith(optionalPeerDepNamespace)) {
const path = id.slice(optionalPeerDepNamespace.length)
const [, peerDep, parentDep] = path.split(':')
return {
code:
'module.exports = {};' +
`throw new Error(\`Could not resolve "${peerDep}" imported by "${parentDep}". Is it installed?\`)`,
}
}
},
},
transform: {
filter: {
code: assetImportMetaUrlRE,
},
handler(code, id) {
let s: MagicString | undefined
const re = new RegExp(assetImportMetaUrlRE)
const cleanString = stripLiteral(code)
let match: RegExpExecArray | null
while ((match = re.exec(cleanString))) {
const [[startIndex, endIndex], [urlStart, urlEnd]] =
match.indices as Array<[number, number]>
if (hasViteIgnoreRE.test(code.slice(startIndex, urlStart))) continueView on GitHub (pinned to b4d66fee14)