jdx/mise · error · eyre::Report
workspace {kind} ID cannot be empty
Error message
workspace {kind} ID cannot be empty What it means
Thrown while building a ProjectId, mise's provider-namespaced workspace project identifier. ProjectId::new(provider, local_id) and ProjectId::from_str both call validate_id_part, which rejects an empty provider or empty local part before joining them as "provider:local". The {kind} in the message is either "provider" or "project" and tells you which half of the pair is empty.
Source
Thrown at src/task/workspace.rs:65
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl FromStr for ProjectId {
type Err = eyre::Report;
fn from_str(value: &str) -> Result<Self> {
let Some((provider, local_id)) = value.split_once(':') else {
bail!("workspace project ID {value:?} must include a provider namespace");
};
Self::new(provider, local_id)
}
}
fn validate_id_part(kind: &str, value: &str) -> Result<()> {
if value.is_empty() {
bail!("workspace {kind} ID cannot be empty");
}
if value.trim() != value || value.chars().any(char::is_control) {
bail!(
"workspace {kind} ID {value:?} contains surrounding whitespace or control characters"
);
}
if kind == "provider" && value.contains(':') {
bail!("workspace provider ID {value:?} cannot contain ':'");
}
Ok(())
}
/// A project discovered from ecosystem-specific workspace metadata.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub(crate) struct WorkspaceProject {
/// Stable identity used by dependency edges and task scoping.
pub id: ProjectId,
/// Normalized path relative to the workspace root. `.` represents the root.View on GitHub (pinned to 6f52dcdf99)
Solutions
- Fix the identifier so both halves are non-empty, e.g. "cargo:" -> "cargo:core"
- If the id came from [monorepo.projects.<id>] depends / depends_add / depends_remove in mise.toml, re-check every dependency string for a missing local part after the colon
- If the id came from ecosystem metadata, open the source file (go.mod module line, Cargo.toml package name) and give it a real value
- If you implement a WorkspaceProvider, never pass an empty name to ProjectId::new
Example fix
# before (mise.toml) [monorepo.projects."cargo:app"] depends = ["cargo:"] # after [monorepo.projects."cargo:app"] depends = ["cargo:core"]
Defensive patterns
Strategy: validation
Validate before calling
fn check_id(id: &str) -> Result<(), String> {
let Some((provider, local)) = id.split_once(':') else {
return Err(format!("{id:?} has no provider namespace"));
};
if provider.is_empty() || local.is_empty() {
return Err(format!("{id:?} has an empty provider or local part"));
}
Ok(())
}
for dep in &override_depends { check_id(dep)?; } Type guard
fn is_valid_project_id(value: &str) -> bool {
match value.split_once(':') {
Some((provider, local)) => !provider.is_empty() && !local.is_empty(),
None => false,
}
} Try / catch
match id.parse::<ProjectId>() {
Ok(parsed) => parsed,
Err(report) if report.to_string().contains("cannot be empty") => {
// config data issue: surface the offending id and continue with a default
fallback_id()
}
Err(err) => return Err(err),
} Prevention
- Always write dependency ids as provider:local with both halves filled ("cargo:core", "go:example.com/pkg", "node:app")
- Copy ids from actual discovery output instead of typing them
- Lint [monorepo.projects] keys and every depends*/ list in CI with a split-on-colon check
When it happens
Trigger: ProjectId::from_str("cargo:") (split_once(':') yields an empty local_id) when parsing depends/depends_add/depends_remove entries from a [monorepo.projects] override in mise.toml; ProjectId::from_str(":foo") yields kind=provider; a provider calling ProjectId::new(self.id(), "") because ecosystem metadata (e.g. a go.mod module path) parsed to an empty string.
Common situations: A trailing colon left after editing a dependency id in mise.toml; a copied project id whose local part was accidentally deleted; a degenerate go.mod whose module directive unescapes to an empty path; hand-writing override keys without copying an existing discovered id.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- workspace {kind} ID {value:?} contains surrounding whitespac
- workspace project {:?} depends on unknown project {:?}
- removed workspace project {id:?} cannot define other overrid
- workspace project {id:?} has absolute root {root:?}; roots m
- workspace project {id:?} has root {root:?} that escapes the
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/62dd66dd8fe9e127.
Report an issue: GitHub.