{"record":{"id":"e10b5419a7547a66","repo":"denoland/deno","slug":"unable-to-find-npm-package-in-workspace","errorCode":null,"errorMessage":"unable to find npm package in workspace","messagePattern":"unable to find npm package in workspace","errorType":"exception","errorClass":"AnyError","httpStatus":null,"severity":"error","filePath":"cli/tools/publish/unfurl.rs","lineNumber":675,"sourceCode":"        referrer,\n        relative_resolved\n      );\n      Ok(Some(relative_resolved))\n    }\n  }\n\n  fn find_workspace_npm_dep_version(\n    &self,\n    pkg_name: &str,\n  ) -> Result<Version, anyhow::Error> {\n    // todo(#24612): warn when this is also a jsr package telling\n    // people to map the specifiers in the import map\n    let pkg_json = self\n      .workspace_resolver\n      .package_jsons()\n      .find(|pkg| pkg.name.as_deref() == Some(pkg_name))\n      .ok_or_else(|| {\n        anyhow::anyhow!(\"unable to find npm package in workspace\")\n      })?;\n    if let Some(version) = &pkg_json.version {\n      Ok(Version::parse_from_npm(version)?)\n    } else {\n      Err(anyhow::anyhow!(\n        \"missing version in package.json of npm package\",\n      ))\n    }\n  }\n\n  /// Look up the version constraint for a @types/* package from package.json\n  /// dependencies (including devDependencies) or from the import map.\n  fn find_types_package_version_req(\n    &self,\n    types_package_name: &str,\n    referrer: &ModuleSpecifier,\n  ) -> Option<VersionReq> {\n    // check package.json dependencies","sourceCodeStart":657,"sourceCodeEnd":693,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/tools/publish/unfurl.rs#L657-L693","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Fix the specifier spelling in the importing source file to exactly match the package.json `name`.","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.","Re-run `deno publish --dry-run` — unfurling errors surface there before upload."],"exampleFix":"// before: src/mod.ts\nimport { helper } from \"my-pkg\"; // not declared anywhere\n\n# after: add the dependency\n# deno add npm:my-pkg\n# (creates/updates package.json: { \"dependencies\": { \"my-pkg\": \"^1.0.0\" } })","handlingStrategy":"validation","validationCode":"import * as path from 'node:path';\n\nfunction declaredNpmNames(pkgJsons: { name?: string }[]): Set<string> {\n  return new Set(pkgJsons.flatMap((p) => (p.name ? [p.name] : [])));\n}\n// scan sources for bare specifiers and compare against package.json names\n// before invoking publish\nconst declared = declaredNpmNames(await readWorkspacePackageJsons());\nfor (const spec of collectBareSpecifiers(await expand('src/**/*.ts'))) {\n  if (!declared.has(spec)) {\n    throw new Error(`npm package \"${spec}\" is imported but not declared in any package.json`);\n  }\n}","typeGuard":"const isDeclaredNpmPackage = (name: string, declared: Set<string>): boolean =>\n  declared.has(name);","tryCatchPattern":"try {\n  await runDeno(['publish']);\n} catch (e) {\n  if (String(e.message).includes('unable to find npm package in workspace')) {\n    // the source file named in the error imports an undeclared npm package:\n    // run `deno add npm:<pkg>` or fix the specifier, then retry\n  }\n}","preventionTips":["Add npm dependencies with `deno add npm:<pkg>` so they are recorded in package.json.","Audit bare imports before publishing (`deno publish --dry-run` surfaces unfurling errors).","Keep package names and their import sites spelled identically; rename both together."],"tags":["publish","jsr","npm","unfurl","workspace","dependency-resolution"],"backgroundTag":"unresolved-dependency","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}