clockworklabs/SpacetimeDB · error · anyhow::Error

Invalid repository format. Use 'owner/repo' or full git…

Error message

Invalid repository format. Use 'owner/repo' or full git clone URL

What it means

When a `--template` value is treated as a GitHub repository to clone, it must either be a full git URL (git@…, ssh://, http://, https://) or a short `owner/repo` form containing a slash. A bare word with no slash and no URL scheme is rejected before any network call happens.

Solutions

  1. Use the `owner/repo` form: `spacetime init myapp --template clockworklabs/quickstart-chat`
  2. Or paste the full HTTPS clone URL: `--template https://github.com/owner/repo`
  3. If you meant a built-in template, use its documented name or run with `--template ''` to list templates

Example fix

# before
spacetime init myapp --template quickstart
# after
spacetime init myapp --template clockworklabs/quickstart
Defensive patterns

Strategy: validation

Validate before calling

# accept owner/repo or a full URL before calling init
case "$TPL" in */*|git@*|ssh://*|http://*|https://*) spacetime init app --template "$TPL";; *) echo 'use owner/repo or full URL';; esac

Prevention

When it happens

Trigger: Passing `--template quickstart` (single word, no owner) where the CLI expects `--template someuser/quickstart`; passing an SCP-style shorthand that does not start with git@; a typo that drops the slash.

Common situations: Copying a template name from a README that lists only the repo name; mixing up built-in template names with GitHub repo refs; assuming `git@` is optional.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@fdd647dfac (2026-08-20). Data as JSON: /api/errors/d883b268264bc91d. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/subcommands/init.rs:1003

        Some(value) if value.eq_ignore_ascii_case("csharp") || value.eq_ignore_ascii_case("c#") => "C#".to_string(),
        Some(value) if value.eq_ignore_ascii_case("typescript") => "TypeScript".to_string(),
        Some(value) if value.eq_ignore_ascii_case("cpp") || value.eq_ignore_ascii_case("c++") => "C++".to_string(),
        Some(value) if !value.trim().is_empty() => value.to_string(),
        _ => "None".to_string(),
    }
}

fn clone_github_template(repo_input: &str, target: &Path, is_server_only: bool) -> anyhow::Result<()> {
    let is_git_url = |s: &str| {
        s.starts_with("git@") || s.starts_with("ssh://") || s.starts_with("http://") || s.starts_with("https://")
    };

    let repo_url = if is_git_url(repo_input) {
        repo_input.to_string()
    } else if repo_input.contains('/') {
        format!("https://github.com/{}", repo_input)
    } else {
        anyhow::bail!("Invalid repository format. Use 'owner/repo' or full git clone URL");
    };

    println!("  Cloning from {}...", repo_url);

    let temp_dir = tempfile::tempdir()?;

    let mut builder = git2::build::RepoBuilder::new();

    let mut fetch_options = git2::FetchOptions::new();
    let mut callbacks = git2::RemoteCallbacks::new();

    callbacks.credentials(|_url, username_from_url, allowed_types| {
        if allowed_types.contains(git2::CredentialType::SSH_KEY)
            && let Some(username) = username_from_url
        {
            return git2::Cred::ssh_key_from_agent(username);
        }
        if allowed_types.contains(git2::CredentialType::USER_PASS_PLAINTEXT) {

View on GitHub (pinned to fdd647dfac)