jdx/mise · error
backend must be a string or table
Error message
backend must be a string or table
What it means
In parse_registry_backend, each element of a registry entry's backends array must be either a plain string (shorthand like "aqua:owner/repo") or a TOML table with full/platforms/options fields. Any other TOML type — integer, float, boolean, array, or datetime — falls through to this bail and the registry fails to load.
Source
Thrown at src/registry.rs:502
.map(|options| {
options
.iter()
.map(|(key, value)| {
let mut serialized = String::new();
value.serialize(toml::ser::ValueSerializer::new(&mut serialized))?;
Ok((leak_string(key.clone()), leak_string(serialized)))
})
.collect::<Result<Vec<_>>>()
})
.transpose()?
.unwrap_or_default();
Ok(RegistryBackend {
full: leak_string(full.to_string()),
platforms: leak_vec(platforms),
options: leak_vec(options),
})
}
_ => bail!("backend must be a string or table"),
}
}
fn parse_registry_test(value: &toml::Value) -> Result<RegistryToolTest> {
let table = value
.as_table()
.ok_or_else(|| eyre::eyre!("test must be a table"))?;
let cmd = table
.get("cmd")
.and_then(toml::Value::as_str)
.ok_or_else(|| eyre::eyre!("test.cmd must be a string"))?;
let expected = table
.get("expected")
.and_then(toml::Value::as_str)
.ok_or_else(|| eyre::eyre!("test.expected must be a string"))?;
let tools = string_array(table.get("tools"), "test.tools")?;
Ok(RegistryToolTest {
cmd: leak_string(cmd.to_string()),View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Use the string form for simple cases: backends = ["aqua:cli/cli"].
- Use the table form only when you need full/platforms/options: backends = [{ full = "aqua:cli/cli", platforms = ["linux", "macos"] }].
- Ensure the backends array itself is non-empty — an empty array is rejected separately just above this code.
- Validate with the registry test suite (`cargo test registry`) before submitting.
Example fix
# before backends = [["aqua:cli/cli"]] # after backends = ["aqua:cli/cli"]
Defensive patterns
Strategy: validation
Validate before calling
# every backends[] element must be a string or a table
python3 - <<'EOF'
import sys, tomllib
cfg = tomllib.load(open('registry/mytool.toml','rb'))
for b in cfg['tools']['mytool']['backends']:
if not isinstance(b, (str, dict)):
sys.exit(f'backend must be a string or table, got: {b!r}')
EOF Type guard
def is_registry_backend(v) -> bool: return isinstance(v, (str, dict))
Prevention
- Prefer the one-line string form: backends = ["aqua:owner/repo"].
- Never wrap backends entries in extra brackets.
- Lint TOML with a schema-aware tool before contributing.
When it happens
Trigger: Writing backends = [123], backends = [true], backends = [["aqua:owner/repo"]], or backends = [1979-05-27] in a registry/*.toml entry. Also triggered by YAML-to-TOML conversions that turn a single backend string into a nested array.
Common situations: Contributing a registry entry and wrapping the backend in extra brackets; automated tooling that emits a non-string scalar; merging registry entries by hand and leaving a stray value.
Related errors
- {self} is in the mise tool registry but none of its backends
- version_order must be "source" or "semver"
- expected `run` to be a string or array of strings
- expected a string, array of strings, or table with `run`
- {message}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/6db639cfe029f835.
Report an issue: GitHub.