Skip to content

SideRepoOps: creating a PR against a non-default branch generates E003 without a custom DEFAULT_BRANCH override #31086

Closed

Description

@yskopets

Summary

When using the SideRepoOps pattern to create a PR against a non-default branch of the target repository, the default safeoutputs configuration generates an E003 error (patch exceeds the 100-file limit), making it impossible to open the PR without a custom workaround.

Root Cause

safeoutputs computes the patch as diff(origin/$DEFAULT_BRANCH, HEAD). In a SideRepoOps setup, DEFAULT_BRANCH is automatically set to the default branch of the checked-out target repo (typically master or main).

When the agentic workflow is designed to operate on a non-default release branch (e.g. release-1.12.x), the agent switches to that branch after checkout. The diff baseline, however, remains origin/master. The resulting patch includes every file that diverges between master and the release branch — potentially hundreds or thousands of files — far exceeding the 100-file limit, even if the agent's actual change is just 1–2 files.

Failure Sequence

  1. checkout step starts at master → DEFAULT_BRANCH=master
  2. Agent reads the target branch from the issue and runs git checkout release-1.12.x
  3. safeoutputs computes diff(origin/master, HEAD) = ~hundreds of files + the actual fix
  4. E003: patch exceeds 100-file limit → PR is not created

Workaround

We added a pre-step between checkout and the agent job that:

  1. Reads the target branch from a branch/<name> issue label
  2. Re-anchors the git checkout to that branch
  3. Writes DEFAULT_BRANCH=<branch> to $GITHUB_ENV so safeoutputs uses origin/<branch> as the patch baseline
- name: Re-anchor checkout to target release branch
  shell: bash
  env:
    GH_TOKEN: ${{ steps.app-token.outputs.token }}
  run: |
    # safeoutputs generates the patch as diff(origin/$DEFAULT_BRANCH, HEAD).
    # The checkout above starts at master, so DEFAULT_BRANCH=master and the patch
    # baseline is origin/master. If the agent then switches to a release branch,
    # the patch includes all files that diverge between master and that
    # release branch plus the actual fix — far exceeding the 100-file limit.
    # Fix: read the target branch from the issue's branch/<name> label, re-anchor
    # the checkout to that branch, and override DEFAULT_BRANCH so safeoutputs
    # computes diff(origin/release-X.Y.x, HEAD) = just the actual fix.
    ISSUE_NUMBER="${{ github.event.issue.number || github.event.inputs.issue_number }}"
    if [ -z "$ISSUE_NUMBER" ]; then
      echo "Error: no issue number available"
      exit 1
    fi
    # Read the target branch from the issue's branch/<name> label.
    # Exactly one such label is required — zero or multiple are a hard error.
    mapfile -t BRANCH_LABELS < <(gh issue view "$ISSUE_NUMBER" --repo <target-repo> --json labels \
      -q '.labels[] | .name | select(startswith("branch/"))')
    if [ "${#BRANCH_LABELS[@]}" -ne 1 ]; then
      echo "Error: issue must have exactly one branch/<name> label, found ${#BRANCH_LABELS[@]}: ${BRANCH_LABELS[*]}"
      exit 1
    fi
    BRANCH="${BRANCH_LABELS[0]#branch/}"
    if [[ \! "$BRANCH" =~ ^(master|release-[0-9]+\.[0-9]+\.x)$ ]]; then
      echo "Error: branch/<name> label '${BRANCH}' does not match expected pattern"
      exit 1
    fi
    echo "Re-anchoring checkout from master to ${BRANCH}"
    git -C <repo-path> checkout -B "$BRANCH" "origin/$BRANCH"
    git -C <repo-path> remote set-head origin "$BRANCH"
    # Override DEFAULT_BRANCH so the safeoutputs patch baseline is origin/$BRANCH
    # instead of origin/master (which would include all master→release divergence).
    echo "DEFAULT_BRANCH=$BRANCH" >> "$GITHUB_ENV"

Suggested Improvement

This workaround is non-obvious, requires understanding safeoutputs internals, and has to be re-implemented by every workflow author that needs to target a non-default branch.

A few possible fixes:

  1. Document the pattern in the SideRepoOps guide with an explicit note that DEFAULT_BRANCH must be overridden when the agent targets a non-default branch.

  2. Add a base-branch option to checkout that, when set, automatically writes DEFAULT_BRANCH=<branch> to $GITHUB_ENV after the checkout completes — removing the need for a custom pre-step entirely.

  3. Derive DEFAULT_BRANCH from the branch the agent is actually on at the time safeoutputs runs (rather than from the repo's default branch at checkout time).

Option 2 or 3 would be the most ergonomic; option 1 is the minimal acceptable fix.


Reported by Claude (claude-sonnet-4-6) based on a SideRepoOps workflow that creates PRs against versioned release branches.

Activity

  1. locked and limited conversation to collaborators on May 8, 2026
  2. unlocked this conversation on May 8, 2026
  3. pelikhan commented on May 16, 2026

    @pelikhan
    Collaborator

    @copilot implement option 3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions