warpdotdev/warp · error
Invalid repo format: '{}'. Expected format: 'owner/repo'
Error message
Invalid repo format: '{}'. Expected format: 'owner/repo' What it means
Thrown by parse_repos() in app/src/ai/agent_sdk/environment.rs when a --repo argument cannot be split on '/' into exactly two non-empty parts ('owner' and 'repo'). The value is converted into a GithubRepo via GithubRepo::new(parts[0], parts[1]), so any string that is not a bare 'owner/repo' slug is rejected before any network or Warp Drive work starts. It surfaces as a fatal CLI error from the environment create/update commands, which call parse_repos on the repo and remove_repo arguments.
Source
Thrown at app/src/ai/agent_sdk/environment.rs:48
use crate::cloud_object::{CloudObject, CloudObjectLookup as _};
use crate::server::cloud_objects::update_manager::{
ObjectOperation, OperationSuccessType, UpdateManager, UpdateManagerEvent,
};
use crate::server::ids::{ClientId, ServerId, SyncId};
use crate::server::server_api::ServerApiProvider;
use crate::util::time_format::format_approx_duration_from_now_utc;
use crate::workspaces::user_profiles::UserProfiles;
const WARP_DEV_ENVIRONMENTS_REPO: &str = "https://github.com/warpdotdev/warp-dev-environments";
/// Parse repo strings in the format "owner/repo" into GithubRepo objects.
fn parse_repos(repo_strings: Vec<String>) -> anyhow::Result<Vec<GithubRepo>> {
repo_strings
.into_iter()
.map(|r| {
let parts: Vec<&str> = r.split('/').collect();
if parts.len() != 2 {
return Err(anyhow::anyhow!(
"Invalid repo format: '{}'. Expected format: 'owner/repo'",
r
));
}
Ok(GithubRepo::new(parts[0].to_string(), parts[1].to_string()))
})
.collect()
}
/// Handle environment-related CLI commands.
pub fn run(
ctx: &mut AppContext,
global_options: GlobalOptions,
command: EnvironmentCommand,
) -> anyhow::Result<()> {
let runner = ctx.add_singleton_model(|_ctx| EnvironmentCommandRunner);
match command {
EnvironmentCommand::List => {View on GitHub (pinned to e72fd7aacb)
Solutions
- Pass the bare slug: `--repo owner/repo` (e.g. `--repo warpdotdev/warp-dev-environments`), not a URL or SSH remote
- If your source is a URL, strip the scheme and host first (keep only the last two path segments)
- Check for trailing/leading slashes and empty strings in scripted arguments before invoking the CLI
- If you must accept URLs in tooling, pre-validate with a split('/').len() == 2 check and normalize to owner/repo
Example fix
# before warp environment create --name dev --repo https://github.com/warpdotdev/warp-dev-environments # after warp environment create --name dev --repo warpdotdev/warp-dev-environments
Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate before calling the CLI/parse_repos
fn is_valid_repo_spec(s: &str) -> bool {
let parts: Vec<&str> = s.split('/').collect();
parts.len() == 2 && !parts[0].is_empty() && !parts[1].is_empty()
}
// Normalize a pasted URL to owner/repo before passing it
fn normalize_repo_input(s: &str) -> Option<String> {
let slug = s.trim().trim_start_matches("https://github.com/")
.trim_start_matches("http://github.com/");
let parts: Vec<&str> = slug.split('/').collect();
if parts.len() >= 2 {
Some(format!("{}/{}", parts[parts.len() - 2], parts[parts.len() - 1]))
} else {
None
}
} Type guard
fn is_owner_repo_slug(s: &str) -> bool {
matches!(s.split('/').collect::<Vec<_>>()[..], [o, r] if !o.is_empty() && !r.is_empty())
} Try / catch
// parse_repos returns anyhow::Result — handle it at the call site
match parse_repos(repo_strings) {
Ok(repos) => { /* proceed */ },
Err(err) => eprintln!("bad --repo argument: {err}"),
} Prevention
- Always pass the bare 'owner/repo' slug, never a full URL or SSH remote
- In scripts, run a split('/').len() == 2 assertion on every --repo value before invoking the CLI
- Strip whitespace from interpolated variables holding repo values
- Document the expected format wherever the CLI is scripted for others
When it happens
Trigger: Running `warp environment create --repo <value>` or `warp environment update --repo <value>` where value is a full GitHub URL (e.g. https://github.com/warpdotdev/warp-dev-environments splits into 5+ parts), a bare repo name ('myrepo' splits into 1 part), a trailing/leading slash ('owner/repo/' splits into 3 parts), or an empty string.
Common situations: Users pasting a repo URL copied from the browser instead of the owner/repo slug; scripts that pass git remotes (git@github.com:owner/repo.git) verbatim; shell quoting that swallows or adds slashes; trailing slash after tab-completion.
Related errors
- Invalid repo format: '{}'. Expected 'owner/repo' or 'https:/
- Environment {} not found
- Exceeded maximum number of authorization attempts ({}). Plea
- GitHub authorization failed. Please try again.
- GitHub authorization expired. Please try again.
AI-assisted analysis of warpdotdev/warp@e72fd7aacb (2026-08-16).
Data as JSON: /api/errors/c36c53ec8323e69a.
Report an issue: GitHub.