denoland/deno · error · AnyError

is missing 'version' field

Error message

{} is missing 'version' field

What it means

Every package published to JSR must carry a version, so `deno publish` reads `version` from the member's deno.json (`deno_json.json.version`) during preparation and refuses to continue when the field is absent. The message names the exact config file specifier that is missing the field. This is checked per workspace member, so one member without a version fails the whole publish.

Solutions

  1. Open the deno.json named in the error and add a valid semver version, e.g. `"version": "1.0.0"`.
  2. In a workspace, reuse the root version with `"version": "workspace:..."` so members stay in sync with the root's `version` field.
  3. Ensure the version is a plain semver string (no 'v' prefix, no range operators) — JSR rejects those at upload anyway.
  4. Re-run `deno publish --dry-run` to confirm the member now passes preparation.

Example fix

// before (member deno.json)
{
  "name": "@scope/util",
  "exports": "./mod.ts"
}

// after
{
  "name": "@scope/util",
  "version": "workspace:...",
  "exports": "./mod.ts"
}
Defensive patterns

Strategy: validation

Validate before calling

import { readManifest } from './deps.ts';
const denoJson = JSON.parse(await Deno.readText(memberDenoJsonPath));
if (!denoJson.version && denoJson.version !== 'workspace:...') {
  throw new Error(`${memberDenoJsonPath} is missing 'version' field`);
}

Type guard

function isPublishableManifest(
  m: Record<string, unknown>,
): boolean {
  return typeof m.name === 'string' &&
    (typeof m.version === 'string' || m.version === 'workspace:...');
}

Try / catch

try {
  await runDeno(['publish']);
} catch (e) {
  if (String(e.message).includes("missing 'version' field")) {
    // add "version" to the deno.json named in the message, then re-run
  }
}

Prevention

When it happens

Trigger: A workspace member deno.json that declares `name`, `exports`, but no `version`; converting a private workspace package (never published, no version needed) into a publishable one without adding the field; publishing a single-package repo whose deno.json only has name/imports.

Common situations: Workspaces where the root deno.json has a version and the author assumes members inherit it (for deno.json members you must declare `"version": "workspace:..."` or a literal); scaffolding a new member by copying a template that omitted version; YAML/JSON typo like `Version` (fields are case-sensitive).

Related errors


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

Appendix: source

Thrown at cli/tools/publish/mod.rs:523

            );
          }
        }
        Ok(diagnostics_by_folder.into_graph())
      }
    }
  }

  async fn prepare_publish(
    &self,
    package: &JsrPackageConfig,
    graph: Arc<deno_graph::ModuleGraph>,
    diagnostics_collector: &PublishDiagnosticsCollector,
  ) -> Result<Rc<PreparedPublishPackage>, AnyError> {
    let deno_json = &package.config_file;
    let config_path = deno_json.specifier.to_file_path().unwrap();
    let root_dir = config_path.parent().unwrap().to_path_buf();
    let version = deno_json.json.version.clone().ok_or_else(|| {
      deno_core::anyhow::anyhow!(
        "{} is missing 'version' field",
        deno_json.specifier
      )
    })?;
    let (scope, name_no_scope) = registry::parse_package_name(&package.name)?;
    let file_patterns = package.member_dir.to_publish_config()?.files;

    let tarball = deno_core::unsync::spawn_blocking({
      let diagnostics_collector = diagnostics_collector.clone();
      let module_content_provider = self.module_content_provider.clone();
      let cli_options = self.cli_options.clone();
      let config_path = config_path.clone();
      let config_url = deno_json.specifier.clone();
      let has_license_field = package.license.is_some();
      let current_package_name = package.name.clone();
      move || {
        let root_specifier =
          ModuleSpecifier::from_directory_path(&root_dir).unwrap();

View on GitHub (pinned to f7822238ca)