denoland/deno · error

package name must use the '@<scope>/<package>' format

Error message

package name must use the '@<scope>/<package>' format

What it means

`parse_package_name` requires JSR package names to be fully qualified in the `@<scope>/<package>` form. After stripping the leading `@` it must find a `/` separating scope and package; if the name has no leading `@` or no `/` (or the stricter JsrPackageReqReference parse also fails), the name is not a valid JSR package name and this error is raised.

Source

Thrown at cli/registry.rs:242

/// Splits a fully qualified JSR package name (e.g. `@scope/package`) into its
/// `(scope, package)` parts.
pub fn parse_package_name(name: &str) -> Result<(&str, &str), AnyError> {
  // Keep the explicit path-safety checks below even if the JSR grammar changes.
  let reference = JsrPackageReqReference::from_str(&format!("jsr:{name}@*"))
    .map_err(|_| {
      deno_core::anyhow::anyhow!(
        "package name must use the '@<scope>/<package>' format"
      )
    })?;
  if reference.sub_path().is_some() {
    bail!("package name must not contain additional path segments");
  }

  let Some((scope, package)) =
    name.strip_prefix('@').and_then(|name| name.split_once('/'))
  else {
    bail!("package name must use the '@<scope>/<package>' format");
  };
  for component in [scope, package] {
    if component == "." || component == ".." {
      bail!("package name must not contain dot path segments");
    }
    if component
      .chars()
      .any(|c| matches!(c, '/' | '\\' | '?' | '#' | '%'))
    {
      bail!("package name contains a URL path or delimiter character");
    }
  }
  Ok((scope, package))
}

/// Returns `true` if the given package version is already published to the
/// registry.
///

View on GitHub (pinned to f7822238ca)

Solutions

  1. Format the name as `@<scope>/<package>`, e.g. `@my-scope/my-package` instead of `my-package`
  2. Add the missing `@` scope prefix if the scope exists but was dropped
  3. Check the shell/CI variable actually contains the full qualified name (echo it before calling)

Example fix

// before
parse_package_name("my-package")?;
// after
parse_package_name("@my-scope/my-package")?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_qualified_jsr_name(name: &str) -> bool {
  let Some(rest) = name.strip_prefix('@') else { return false };
  match rest.split_once('/') {
    Some((scope, pkg)) => !scope.is_empty() && !pkg.is_empty(),
    None => false,
  }
}
assert!(is_qualified_jsr_name("@my-scope/my-package"));
let (scope, package) = parse_package_name(name)?;

Type guard

fn is_qualified_jsr_name(name: &str) -> bool {
  name.starts_with('@')
    && name.strip_prefix('@').and_then(|r| r.split_once('/'))
      .map(|(s, p)| !s.is_empty() && !p.is_empty())
      .unwrap_or(false)
}

Try / catch

match parse_package_name(name) {
  Ok((scope, package)) => /* use scope/package */,
  Err(e) if e.to_string().contains("'@<scope>/<package>' format") => {
    eprintln!("name must look like @scope/package; got {name:?}");
    std::process::exit(2);
  }
  Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Passing a bare package name (`mypackage`), a scope only (`@my-scope`), an empty string, or a name with a malformed prefix such as `@@scope/pkg` to `parse_package_name` — the `strip_prefix('@').and_then(split_once('/'))` step returns None.

Common situations: Using npm-style unscoped names in a JSR context; forgetting the `@` when typing a scope; shell/CI variables expanding to empty strings; splitting a full name on the wrong delimiter so only the package part survives.

Related errors


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