denoland/deno · error · AnyError

unable to find npm package in workspace

Error message

unable to find npm package in workspace

What it means

While 'unfurling' relative npm imports for publish, Deno resolves a bare npm specifier found in a source file by looking for a workspace package.json whose `name` matches (`find_workspace_npm_dep_version`). If no workspace package.json declares that exact name, resolution fails with this error — effectively the package is imported in code but not part of the workspace under that name.

Solutions

  1. Add the npm dependency properly so it lands in package.json: `deno add npm:my-pkg` (or manually add `"dependencies": {"my-pkg": "^1.0.0" }` to the relevant package.json).
  2. Fix the specifier spelling in the importing source file to exactly match the package.json `name`.
  3. See the adjacent todo (#24612): if the same package also exists on JSR, map it through the deno.json import map instead of relying on the npm workspace entry.
  4. Re-run `deno publish --dry-run` — unfurling errors surface there before upload.

Example fix

// before: src/mod.ts
import { helper } from "my-pkg"; // not declared anywhere

# after: add the dependency
# deno add npm:my-pkg
# (creates/updates package.json: { "dependencies": { "my-pkg": "^1.0.0" } })
Defensive patterns

Strategy: validation

Validate before calling

import * as path from 'node:path';

function declaredNpmNames(pkgJsons: { name?: string }[]): Set<string> {
  return new Set(pkgJsons.flatMap((p) => (p.name ? [p.name] : [])));
}
// scan sources for bare specifiers and compare against package.json names
// before invoking publish
const declared = declaredNpmNames(await readWorkspacePackageJsons());
for (const spec of collectBareSpecifiers(await expand('src/**/*.ts'))) {
  if (!declared.has(spec)) {
    throw new Error(`npm package "${spec}" is imported but not declared in any package.json`);
  }
}

Type guard

const isDeclaredNpmPackage = (name: string, declared: Set<string>): boolean =>
  declared.has(name);

Try / catch

try {
  await runDeno(['publish']);
} catch (e) {
  if (String(e.message).includes('unable to find npm package in workspace')) {
    // the source file named in the error imports an undeclared npm package:
    // run `deno add npm:<pkg>` or fix the specifier, then retry
  }
}

Prevention

When it happens

Trigger: Source contains `import ... from "my-pkg"` but no package.json in the workspace has `"name": "my-pkg"` (missing dependency, typo'd name, or a dependency that exists only in deno.json imports); importing a npm package that was never added via `deno add npm:my-pkg` in an npm-managed publish setup.

Common situations: JSR packages that also use npm deps and rely on the import map instead of package.json; renaming a local package but not its importers; scaffolding a publish from a repo where the npm dep was resolved through node_modules ad hoc.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e10b5419a7547a66. Report an issue: GitHub.

Appendix: source

Thrown at cli/tools/publish/unfurl.rs:675

        referrer,
        relative_resolved
      );
      Ok(Some(relative_resolved))
    }
  }

  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

View on GitHub (pinned to 9ad36f7a2c)