Hmbown/CodeWhale · error

refusing to push onto the forge default branch

Error message

refusing to push onto the forge default branch {branch}

What it means

push_branch never force-pushes and additionally refuses to push to any branch the forge considers a default branch (e.g. main, master). This protects the repository's primary branch from being rewritten or polluted by dispatch jobs.

Solutions

  1. Use a distinct feature/agent branch name for the dispatch job (e.g. codewhale/<task>)
  2. Fix the job config so the branch field is set explicitly to a non-default name
  3. Verify the branch derivation logic in your tooling isn't falling back to HEAD's default branch

Example fix

// before
push_branch(repo, remote_url, "main")
// after
push_branch(repo, remote_url, "codewhale/fix-logging")
Defensive patterns

Strategy: validation

Validate before calling

if is_forge_default_branch(&branch) {
    branch = format!("codewhale/{}", task_slug); // pick a safe branch
}

Prevention

When it happens

Trigger: push_branch is called (via open) with a branch name for which cloud_dispatch::is_forge_default_branch returns true, e.g. branch="main".

Common situations: Configuring the dispatch job with an empty or wrongly-named branch that resolves to the default, running a job from inside a checkout whose working branch is main, or a template that fills the branch with the repo default.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/014e54971f840af1. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/dispatch_runner.rs:527

    )
    .context("could not set the agent identity")?;
    git(Some(&repo), &["checkout", "--quiet", "-b", &job.branch])
        .context("could not create the cloud agent branch")?;
    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}"),
        ],
    )

View on GitHub (pinned to 73e0f67d83)