astrid-runtime/astrid · error
distro source '{source}' must use @owner/repo, a URL, a loca
Error message
distro source '{source}' must use @owner/repo, a URL, a local Distro.toml path, or a .shuttle archive What it means
resolve_distro_url only accepts a repo path in @owner/repo form; a source that looks like a bare repo path but doesn't split into exactly two non-empty '/'-separated segments is rejected. The source must instead be a URL, a local Distro.toml path, or a .shuttle archive.
Source
Thrown at crates/astrid-cli/src/commands/init.rs:322
/// Resolve an explicit remote distro source string to a URL.
///
/// - `@org/repo` → `https://raw.githubusercontent.com/org/repo/main/Distro.toml`
/// - `https://...` → as-is
///
/// A bare name has no provenance and is rejected rather than being silently
/// assigned to an organization by the neutral runtime.
pub(super) fn resolve_distro_url(source: &str) -> anyhow::Result<String> {
if source.starts_with("http://") || source.starts_with("https://") {
Ok(source.to_string())
} else if let Some(repo_path) = source.strip_prefix('@') {
let mut segments = repo_path.split('/');
let valid = matches!(
(segments.next(), segments.next(), segments.next()),
(Some(owner), Some(repo), None) if !owner.is_empty() && !repo.is_empty()
);
if !valid {
bail!(
"distro source '{source}' must use @owner/repo, a URL, a local Distro.toml path, or a .shuttle archive"
);
}
Ok(format!(
"https://raw.githubusercontent.com/{repo_path}/main/Distro.toml"
))
} else {
bail!(
"distro source '{source}' must use @owner/repo, a URL, a local Distro.toml path, or a .shuttle archive"
)
}
}
/// Parse a comma-separated multi-select entry into a deduped, ordered list
/// of 1-based indices, dropping anything out of `[1, count]` or unparseable.
///
/// Order follows the user's entry; duplicates are collapsed to the first
/// occurrence so selecting `1,1,2` installs each provider once.View on GitHub (pinned to affd8760f4)
Solutions
- Use the full GitHub shorthand: @owner/repo (exactly two non-empty segments).
- Or pass a full URL to the distro's Distro.toml.
- Or point at a local Distro.toml file path or a .shuttle archive.
Example fix
// before astrid init --source mydistro // after astrid init --source @acme/mydistro
Defensive patterns
Strategy: validation
Validate before calling
fn is_owner_repo(s: &str) -> bool {
let s = s.strip_prefix('@').unwrap_or(s);
let parts: Vec<_> = s.split('/').collect();
parts.len() == 2 && parts.iter().all(|p| !p.is_empty())
} Try / catch
match resolve_distro_url(source) {
Ok(url) => fetch(url),
Err(e) => eprintln!("invalid source: {e:#}"),
} Prevention
- Use @owner/repo exactly (two non-empty segments) for GitHub shorthand.
- Strip trailing slashes and extra path segments when building sources in scripts.
- Remember bare distro names have no default registry — always qualify.
When it happens
Trigger: Passing a distro source that is neither a URL, a local Distro.toml path, a .shuttle archive, nor a two-segment non-empty owner/repo path — e.g. `--source mydistro` (bare name), `--source owner/` (empty repo), or `--source a/b/c`.
Common situations: Typing just a distro name expecting a registry-style default lookup; extra path segments pasted from a GitHub URL; trailing slash from shell completion.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Distro.toml has no parent directory
- --retain-entries must be at least 1
- --retain-bytes must be greater than 0
- --var has an empty key (got {item:?})
- --var '{key}' was supplied more than once
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9ea440244d95b579.
Report an issue: GitHub.