denoland/deno · error · AnyError
missing version in package.json of npm package
Error message
missing version in package.json of npm package
What it means
Companion to 'unable to find npm package in workspace': the specifier DID match a workspace package.json by name, but that package.json has no top-level `version` field, so Deno cannot determine which version to unfurl the specifier to. Deno reads `pkg_json.version` and parses it with `Version::parse_from_npm`, requiring a plain semver string.
Solutions
- Add a plain semver `"version": "1.0.0"` (or the real version) to the matched package's package.json.
- Ensure the value is a bare semver version — no 'v' prefix, no range operators like '^'/'~' (Version::parse_from_npm rejects those).
- If the import was accidental (leftover from prototyping), remove the import or redirect it to the correct dependency instead of versioning a dummy package.
Example fix
// before (package.json)
{
"name": "my-pkg",
"exports": "./mod.ts"
}
// after
{
"name": "my-pkg",
"version": "1.0.0",
"exports": "./mod.ts"
} Defensive patterns
Strategy: validation
Validate before calling
const pkgJson = JSON.parse(await Deno.readText('package.json'));
if (typeof pkgJson.version !== 'string' || !/^\d+\.\d+\.\d+/.test(pkgJson.version)) {
throw new Error('workspace npm package needs a plain semver "version" field');
} Type guard
function hasSemverVersion(m: { version?: unknown }): boolean {
return typeof m.version === 'string' && /^\d+\.\d+\.\d+(-[\w.-]+)?$/.test(m.version);
} Try / catch
try {
await runDeno(['publish']);
} catch (e) {
if (String(e.message).includes('missing version in package.json')) {
// add "version": "1.0.0" to the matching package.json, then retry
}
} Prevention
- Give every workspace package.json a version, even internal-only packages.
- Use a bare semver string (no 'v' prefix, no ^/~) since the value is parsed with parse_from_npm.
- Include a version check in pre-publish CI validation of workspace manifests.
When it happens
Trigger: A local workspace npm package whose package.json omits `version` (common for private app crates where version is irrelevant); a version field set to a non-semver value would instead fail parsing; the package is imported by a JSR package being published, triggering the lookup.
Common situations: Monorepos mixing an npm package (never published, no version) with a JSR package that imports it; templates generated without version; users surprised that internal-use packages still need version when referenced from publishable code.
Related errors
- unable to find npm package in workspace
- Cannot represent compiler option
- is missing 'version' field
- Unexpected package json dependency string
- Cannot use --set-version when publishing a workspace…
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/2abb73c81cbf65ae.
Report an issue: GitHub.
Appendix: source
Thrown at cli/tools/publish/unfurl.rs:680
}
fn find_workspace_npm_dep_version(
&self,
pkg_name: &str,
) -> Result<Version, anyhow::Error> {
// todo(#24612): warn when this is also a jsr package telling
// people to map the specifiers in the import map
let pkg_json = self
.workspace_resolver
.package_jsons()
.find(|pkg| pkg.name.as_deref() == Some(pkg_name))
.ok_or_else(|| {
anyhow::anyhow!("unable to find npm package in workspace")
})?;
if let Some(version) = &pkg_json.version {
Ok(Version::parse_from_npm(version)?)
} else {
Err(anyhow::anyhow!(
"missing version in package.json of npm package",
))
}
}
/// Look up the version constraint for a @types/* package from package.json
/// dependencies (including devDependencies) or from the import map.
fn find_types_package_version_req(
&self,
types_package_name: &str,
referrer: &ModuleSpecifier,
) -> Option<VersionReq> {
// check package.json dependencies
let referrer_path = deno_path_util::url_to_file_path(referrer).ok();
let referrer_pkg_jsons = referrer_path
.as_ref()
.map(|path| self.pkg_json_resolver.get_closest_package_jsons(path))
.into_iter()View on GitHub (pinned to 9ad36f7a2c)