Skip to content

gh pr merge refuses when ruleset bypass authority would resolve the block #13388

Description

@dadcoachengineer

Description

When the calling user has ruleset bypass authority that would resolve a mergeStateStatus: BLOCKED PR (e.g., via bypass_actors with bypass_mode: pull_request matching the user's RepositoryRole), gh pr merge refuses at pre-flight rather than attempting the merge. The error offers --admin
or --auto as escape hatches, neither of which fits what the user actually needs.

The underlying REST API merge endpoint (PUT /repos/{owner}/{repo}/pulls/{n}/merge) does engage bypass correctly when called directly. So the gap
is in gh pr merge's pre-flight logic, not in the API.

For repositories using rulesets with bypass_actors as a deliberate design choice — codifying who can self-merge per design intent rather than via
admin override — this means every PR by a bypass-eligible user falls back to --admin. Bypass becomes configured-but-unused; admin overrides
accumulate as if the rule were misconfigured.

Reproduction

  1. Configure a ruleset on main with required_approving_review_count: 1 and:

    "bypass_actors": [
      {
        "actor_id": 5,
        "actor_type": "RepositoryRole",
        "bypass_mode": "pull_request"
      }
    ]
    
  2. As the bypass-eligible user (here, a repo admin — RepositoryRole=5), open a PR. The PR will have:
    - mergeStateStatus: BLOCKED
    - reviewDecision: REVIEW_REQUIRED
    - reviewCount: 0

  3. Confirm bypass eligibility — GET /repos/{owner}/{repo}/rulesets/{id} returns:

"current_user_can_bypass": "pull_requests_only"
4. Try gh pr merge:

$ gh pr merge <PR#> --squash --delete-branch
X Pull request /#<PR#> is not mergeable: the base branch policy prohibits the merge.
To have the pull request merged after all the requirements have been met, add the --auto flag.
To use administrator privileges to immediately merge the pull request, add the --admin flag.
5. Call the REST merge endpoint directly — succeeds, bypass engages:

$ gh api repos///pulls/<PR#>/merge -X PUT -f merge_method=squash
{"sha":"...","merged":true,"message":"Pull Request successfully merged"}

Expected behavior

gh pr merge should detect bypass eligibility before refusing. Two reasonable fix shapes:

  • Conservative: if mergeStateStatus: BLOCKED but current_user_can_bypass indicates bypass-via-pull_request, attempt the merge — the API will engage
    bypass automatically.
  • Simpler: always attempt the API merge and let GitHub's response be authoritative. Bypass engages or it doesn't, and either way the API's response is
    meaningful (success, or a real error worth surfacing). The current pre-flight refusal pre-empts an outcome the API would have produced correctly.

Actual behavior

gh pr merge refuses based purely on mergeStateStatus: BLOCKED without checking bypass authority. Suggested escape hatches:

  • --admin works but is structurally the wrong fit — admin override loudly overrides a rule that the user is in fact authorized to bypass per design.
  • --auto doesn't engage bypass either; auto-merge waits for the original blockers to resolve, which (with bypass authority) won't happen organically.

gh version

gh version 2.90.0 (2026-04-16)

Why this matters

Rulesets with bypass_actors are a natural way to encode "who can self-merge" per design intent for repos with mixed-author models (e.g., bot-authored
PRs requiring review; human-authored PRs not). When gh pr merge doesn't respect bypass, the design becomes ceremony that doesn't deliver: operators
fall back to --admin per PR, repeated admin override erodes the rule's authority, and the codified bypass goes unused.

Current workaround: shell wrapper around gh api .../pulls/{n}/merge -X PUT. Functional but loses the ergonomic value of gh pr merge (mergeStateStatus
visibility, branch deletion semantics, default merge method from repo settings, etc.).

Upstream context

  • GitHub Rulesets REST API: https://docs.github.com/en/rest/repos/rules
  • current_user_can_bypass field: returned on GET /repos/{owner}/{repo}/rulesets/{id} — could serve as the pre-flight signal gh pr merge is currently
    missing
    EOF

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementa request to improve CLIgh-prrelating to the gh pr commandpitchpitched internally for prioritisation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions