jdx/mise · error
backends must not be empty
Error message
backends must not be empty
What it means
This error is thrown while parsing a registry tool's TOML table: after reading the 'backends' array (which itself must be present and an array), the loader requires the array to contain at least one backend. A tool declaration with an empty backends list is considered invalid because the tool would have no installable source.
Solutions
- Add at least one valid backend entry to the tool's backends array
- Remove the tool entry entirely if it should not be in the registry
- Check generated/templated registry files for filters that remove all backends
Example fix
// before
[tools.node]
backends = []
// after
[tools.node]
backends = [
{ backend = "core", ... }
] Defensive patterns
Strategy: validation
Validate before calling
fn validate_backends(table: &toml::Value) -> Result<(), String> {
let arr = table.get("backends").and_then(|v| v.as_array())
.ok_or("backends must be a non-empty array")?;
if arr.is_empty() { return Err("backends must not be empty".into()); }
Ok(())
} Type guard
fn has_backends(tool: &toml::Value) -> bool {
tool.get("backends").and_then(|v| v.as_array()).map_or(false, |a| !a.is_empty())
} Prevention
- Validate registry TOML in CI before merging changes
- Don't leave empty arrays behind when commenting out backends — remove the tool entry
- Check template generators never emit `backends = []`
When it happens
Trigger: Defining a registry tool with `backends = []` in registry TOML, or constructing the array programmatically (e.g. via templating) such that it ends up empty.
Common situations: Commenting out or deleting all backend entries while leaving the empty array behind; template/CI generation that filters out all backends; copy-pasting a tool entry and removing backends before filling them in.
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
- backend min_version requires version_order = "semver"
- unknown idiomatic file field
- backend must be a string or table
- command wrapper for must have a non-blank command
- [daemons. ] requires preset when specifying version or…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/bc132ab03fcc9ebf.
Report an issue: GitHub.
Appendix: source
Thrown at src/registry.rs:418
for alias in tool.aliases {
entries.insert((*alias).to_string(), tool.clone());
}
}
Ok(Registry::dynamic(entries, missing_version_order))
}
fn parse_registry_tool(short: &str, value: &toml::Value) -> Result<(RegistryTool, bool)> {
let table = value
.as_table()
.ok_or_else(|| eyre::eyre!("registry tool must be a TOML table"))?;
let backends = table
.get("backends")
.and_then(toml::Value::as_array)
.ok_or_else(|| eyre::eyre!("backends must be an array"))?
.iter()
.map(parse_registry_backend)
.collect::<Result<Vec<_>>>()?;
ensure!(!backends.is_empty(), "backends must not be empty");
let missing_version_order = !table.contains_key("version_order");
let version_order = match table.get("version_order").and_then(toml::Value::as_str) {
Some("source") => VersionOrder::Source,
Some("semver") => VersionOrder::Semver,
Some(_) => bail!("version_order must be \"source\" or \"semver\""),
None => VersionOrder::Source,
};
ensure!(
version_order == VersionOrder::Semver || backends.iter().all(|b| b.min_version.is_none()),
"backend min_version requires version_order = \"semver\""
);
let aliases = string_array(table.get("aliases"), "aliases")?;
let bins = if table.contains_key("bins") {
string_array(table.get("bins"), "bins")?
} else {
BAKED_REGISTRYView on GitHub (pinned to 533346cc37)