Skip to content

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

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 masterDEFAULT_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.

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions