Hmbown/CodeWhale · error
refusing to push to a non-forge remote
Error message
refusing to push to a non-forge remote
What it means
push_branch validates the remote URL twice: it must be a syntactically valid git remote, and if it looks like a network remote (http(s)/ssh) it must classify as a known forge (GitHub/GitLab etc.). Pushing dispatch output to a non-forge network remote is refused.
Solutions
- Point the remote at a supported forge (github.com/gitlab.com etc.)
- Add the repository as a recognized forge if your version supports custom forge hosts
- Use an SSH/URL form the classifier accepts, or verify the URL spelling
Example fix
// before push_branch(repo, "https://git.mycompany.internal/team/repo.git", branch) // after push_branch(repo, "https://github.com/team/repo.git", branch)
Defensive patterns
Strategy: validation
Validate before calling
if classify_url(&remote_url).is_none() {
// remote is not a supported forge; reconfigure the remote
} Prevention
- Use remotes hosted on supported forges for dispatch jobs
- Double-check remote URL spelling and scheme
- Keep self-hosted forges out of dispatch workflows unless supported
When it happens
Trigger: push_branch receives a remote_url that looks like a network URL (https://git.example.com/...) but cloud_dispatch::classify_url cannot recognize it as a supported forge.
Common situations: Self-hosted or niche forges not in the classifier, push mirrors, generic git servers, or a mistyped URL whose host isn't a recognized forge domain.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- remote url contains control characters
- remote url is empty or oversized
- remote url is not a supported forge
- remote url must not embed userinfo
- A full Git history is required to establish the PR merge…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/47fe3bf28904eb48.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/dispatch_runner.rs:531
git(
Some(&repo),
&["am", "--quiet", "--3way", &patch_path.to_string_lossy()],
)
.context("the agent patch did not apply cleanly onto the target branch")?;
git(Some(&repo), &["rev-parse", "HEAD"]).map(|out| out.trim().to_string())
}
/// Push the prepared branch. Plain push only — `--force` is never passed, so
/// an existing branch that is not a fast-forward fails closed instead of
/// rewriting the target's history.
fn push_branch(repo: &Path, remote_url: &str, branch: &str) -> Result<()> {
let remote_url = cloud_dispatch::validate_git_remote_url(remote_url)?;
if cloud_dispatch::is_forge_default_branch(branch) {
bail!("refusing to push onto the forge default branch {branch}");
}
if looks_like_network_remote(&remote_url) && cloud_dispatch::classify_url(&remote_url).is_none()
{
bail!("refusing to push to a non-forge remote");
}
if remote_branch_exists(&remote_url, branch)? {
bail!("refusing to update existing remote branch {branch}");
}
git(
Some(repo),
&[
"push",
"--quiet",
"--",
&remote_url,
&format!("HEAD:refs/heads/{branch}"),
],
)
.map(|_| ())
.context(
"could not push the cloud agent branch (it may need credentials or the branch may have moved)",
)View on GitHub (pinned to 73e0f67d83)