Skip to content

Duplicate Review Requests When Using gh pr edit --add-reviewer #11097

Description

@Mildwhale

Describe the bug

When running the command gh pr edit --add-reviewer, the specified reviewer receives two review requests instead of one. This causes the reviewer to approve the same pull request twice.

Affected version

gh version 2.74.1 (2025-06-10)
https://github.com/cli/cli/releases/tag/v2.74.1

Steps to reproduce the behavior

  • Run the following command: gh pr edit <PR_NUMBER> --add-reviewer <REVIEWER_IDS>

Expected vs actual behavior

Expected

  • The reviewer should receive only one review request
  • The reviewer should need to approve only once

Actual

  • The reviewer receives two separate review requests
  • The reviewer must approve the PR twice for it to be fully approved

Logs

[git remote -v]
[git config --get-regexp ^remote\..*\.gh-resolved$]
* Request at 2025-06-11 06:47:10.13476036[9](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:10) +0000 UTC m=+0.060470440
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 657
> Content-Type: application/json; charset=utf-8
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

GraphQL query:
query PullRequestByNumber($owner: String!, $repo: String!, $pr_number: Int!) {
    repository(owner: $owner, name: $repo) {
      pullRequest(number: $pr_number) {id,url,title,body,baseRefName,reviewRequests(first: [10](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:11)0) {nodes {requestedReviewer {__typename,...on User{login},...on Team{organization{login}name,slug}}}},labels(first:100){nodes{id,name,description,color},totalCount},milestone{number,title,description,dueOn},assignedActors(first: 10) {nodes {...on User {id,login,name,__typename}...on Bot {id,login,__typename}},totalCount},number}
    }
  }
GraphQL variables: {"owner":"Mildwhale","pr_number":62,"repo":"app-deploy-slack-bot"}

< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, [11](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:12) Jun 2025 06:47:10 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97927:3F1BC29:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4997
< X-Ratelimit-Reset: 1749628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 3
< X-Xss-Protection: 0

{
  "data": {
    "repository": {
      "pullRequest": {
        "id": "PR_kwDOFb5pX86Z-PaA",
        "url": "https://github.com/Mildwhale/app-deploy-slack-bot/pull/62",
        "title": "zzz",
        "body": "",
        "baseRefName": "master",
        "reviewRequests": {
          "nodes": []
        },
        "labels": {
          "nodes": [],
          "totalCount": 0
        },
        "milestone": null,
        "assignedActors": {
          "nodes": [],
          "totalCount": 0
        },
        "number": 62
      }
    }
  }
}

* Request took 216.91861ms
* Request at 2025-06-11 06:47:10.352963763 +0000 UTC m=+0.278673824
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 470
> Content-Type: application/json
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

GraphQL query:
query PullRequestProjectItems($endCursor:String$name:String!$number:Int!$owner:String!){repository(owner: $owner, name: $name){pullRequest(number: $number){projectItems(first: 100, after: $endCursor){nodes{id,project{id,title},status:fieldValueByName(name: "Status"){... on ProjectV2ItemFieldSingleSelectValue{optionId,name}}},pageInfo{hasNextPage,endCursor}}}}}
GraphQL variables: {"endCursor":null,"name":"app-deploy-slack-bot","number":62,"owner":"Mildwhale"}

< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jun 2025 06:47:10 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97A33:3F1BE32:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4996
< X-Ratelimit-Reset: 1749628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 4
< X-Xss-Protection: 0

{
  "data": {
    "repository": {
      "pullRequest": {
        "projectItems": {
          "nodes": [],
          "pageInfo": {
            "hasNextPage": false,
            "endCursor": null
          }
        }
      }
    }
  }
}

* Request took 174.997079ms
* Request at 2025-06-11 06:47:10.528196507 +0000 UTC m=+0.453906588
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 45
> Content-Type: application/json
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

{
  "query": "query UserCurrent{viewer{login}}"
}

* Request at 2025-06-11 06:47:10.528506341 +0000 UTC m=+0.4542164[12](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:13)
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 401
> Content-Type: application/json
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

GraphQL query:
query RepositoryAssignableActors($endCursor:String$name:String!$owner:String!){repository(owner: $owner, name: $name){suggestedActors(first: 100, after: $endCursor, capabilities: CAN_BE_ASSIGNED){nodes{... on User{id,login,name,__typename},... on Bot{id,login,__typename}},pageInfo{hasNextPage,endCursor}}}}
GraphQL variables: {"endCursor":null,"name":"app-deploy-slack-bot","owner":"Mildwhale"}

* Request at 2025-06-11 06:47:10.528706338 +0000 UTC m=+0.454416419
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 278
> Content-Type: application/json
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

GraphQL query:
query OrganizationTeamList($endCursor:String$owner:String!){organization(login: $owner){teams(first: 100, orderBy: {field: NAME, direction: ASC}, after: $endCursor){nodes{id,slug},pageInfo{hasNextPage,endCursor}}}}
GraphQL variables: {"endCursor":null,"owner":"Mildwhale"}

< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jun 2025 06:47:10 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97B1F:3F1C009:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4995
< X-Ratelimit-Reset: 1749628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 5
< X-Xss-Protection: 0

{
  "data": {
    "organization": null
  },
  "errors": [
    {
      "type": "NOT_FOUND",
      "path": [
        "organization"
      ],
      "locations": [
        {
          "line": 1,
          "column": 61
        }
      ],
      "message": "Could not resolve to an Organization with the login of 'Mildwhale'."
    }
  ]
}

* Request took 57.76367ms
< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jun 2025 06:47:10 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97B1E:3F1C002:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4994
< X-Ratelimit-Reset: 1749628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 6
< X-Xss-Protection: 0

{
  "data": {
    "viewer": {
      "login": "github-actions[bot]"
    }
  }
}

* Request took 124.497[14](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:15)8ms
< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jun 2025 06:47:10 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=3[15](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:16)36000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97B1F:3F1C005:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4993
< X-Ratelimit-Reset: [17](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:18)49628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 7
< X-Xss-Protection: 0

{
  "data": {
    "repository": {
      "suggestedActors": {
        "nodes": [
          {
            "id": "MDQ6VXNlcjMxMTM4MTA=",
            "login": "Mildwhale",
            "name": "Kyujin Kim",
            "__typename": "User"
          }
        ],
        "pageInfo": {
          "hasNextPage": false,
          "endCursor": "Mg"
        }
      }
    }
  }
}

* Request took 334.424312ms
* Request at 2025-06-11 06:47:10.863264[18](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:19)2 +0000 UTC m=+0.788974253
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 277
> Content-Type: application/json
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

GraphQL query:
mutation PullRequestUpdateRequestReviews($input:RequestReviewsInput!){requestReviews(input: $input){pullRequest{id}}}
GraphQL variables: {"input":{"pullRequestId":"PR_kwDOFb5pX86Z-PaA","userIds":["MDQ6VXNlcjMxMTM4MTA=","MDQ6VXNlcjMxMTM4MTA="],"teamIds":[],"union":false}}

* Request at 2025-06-11 06:47:10.864124385 +0000 UTC m=+0.789834456
* Request to https://api.github.com/graphql
> POST /graphql HTTP/1.1
> Host: api.github.com
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> Content-Length: 179
> Content-Type: application/json
> Graphql-Features: merge_queue
> Time-Zone: Etc/UTC
> User-Agent: GitHub CLI 2.74.0

GraphQL query:
mutation PullRequestUpdate($input:UpdatePullRequestInput!){updatePullRequest(input: $input){__typename}}
GraphQL variables: {"input":{"pullRequestId":"PR_kwDOFb5pX86Z-PaA"}}

< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jun 2025 06:47:11 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97CE8:3F1C35E:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4991
< X-Ratelimit-Reset: 1749628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 9
< X-Xss-Protection: 0

{
  "data": {
    "requestReviews": {
      "pullRequest": {
        "id": "PR_kwDOFb5pX86Z-PaA"
      }
    }
  },
  "extensions": {
    "warnings": [
      {
        "type": "DEPRECATION",
        "message": "The id MDQ6VXNlcjMxMTM4MTA= is deprecated. Update your cache to use the next_global_id from the data payload.",
        "data": {
          "legacy_global_id": "MDQ6VXNlcjMxMTM4MTA=",
          "next_global_id": "U_kgDOAC-DUg"
        },
        "link": "https://docs.github.com"
      },
      {
        "type": "DEPRECATION",
        "message": "The id MDQ6VXNlcjMxMTM4MTA= is deprecated. Update your cache to use the next_global_id from the data payload.",
        "data": {
          "legacy_global_id": "MDQ6VXNlcjMxMTM4MTA=",
          "next_global_id": "U_kgDOAC-DUg"
        },
        "link": "https://docs.github.com"
      }
    ]
  }
}

* Request took 273.085601ms
< HTTP/2.0 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
< Content-Security-Policy: default-src 'none'
< Content-Type: application/json; charset=utf-8
< Date: Wed, 11 Jun 2025 06:47:11 GMT
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< Server: github.com
< Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
< Vary: Accept-Encoding, Accept, X-Requested-With
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Github-Media-Type: github.v4; param=merge-info-preview.nebula-preview; format=json
< X-Github-Request-Id: A009:223FC2:1F97CE9:3F1C362:6849266E
< X-Ratelimit-Limit: 5000
< X-Ratelimit-Remaining: 4992
< X-Ratelimit-Reset: 1749628029
< X-Ratelimit-Resource: graphql
< X-Ratelimit-Used: 8
< X-Xss-Protection: 0

{
  "data": {
    "updatePullRequest": {
      "__typename": "UpdatePullRequestPayload"
    }
  }
}

* Request took 300.5679[19](https://github.com/Mildwhale/app-deploy-slack-bot/actions/runs/15577973994/job/43866492547#step:5:20)ms

Log Analysis

While analyzing the internal GraphQL request made by the CLI, I found that the userIds field contains the same user ID twice, which likely causes the duplication:

GraphQL query:
mutation PullRequestUpdateRequestReviews($input:RequestReviewsInput!){requestReviews(input: $input){pullRequest{id}}}
GraphQL variables: {"input":{"pullRequestId":"PR_kwDOJ1e7tM6Z-KSE","userIds":["MDQ6VXNlcjMxMTM4MTA=","MDQ6VXNlcjMxMTM4MTA="],"teamIds":["T_kwDOAsZIZs4Afapn"],"union":false}}

As shown above, the same userId is passed twice in the mutation request.

Activity

  1. williammartin commented on Jun 11, 2025

    @williammartin
    Member

    Thanks for the detailed report. Was this an issue in 2.74.0?

  2. Mildwhale commented on Jun 11, 2025

    @Mildwhale
    Author

    Thanks for the detailed report. Was this an issue in 2.74.0?

    Yes, I confirmed that the issue also exists in version 2.74.0 when run in a GitHub Actions environment.
    For reference, I reproduced it with v2.74.1 via CLI as well.

  3. williammartin commented on Jun 11, 2025

    @williammartin
    Member

    Ok then we probably accidentally introduced it in v2.73.0 when we did work around supporting copilot as an issue assignee, https://github.com/cli/cli/releases/tag/v2.73.0 thanks!

  4. williammartin commented on Jun 11, 2025

    @williammartin
    Member

    The bug is in this function

    cli/api/queries_repo.go

    Lines 699 to 730 in 49eee93

    func (m *RepoMetadataResult) MembersToIDs(names []string) ([]string, error) {
    var ids []string
    for _, assigneeLogin := range names {
    found := false
    for _, u := range m.AssignableUsers {
    if strings.EqualFold(assigneeLogin, u.Login()) {
    ids = append(ids, u.ID())
    found = true
    break
    }
    }
    // Look for ID in assignable actors if not found in assignable users
    for _, a := range m.AssignableActors {
    if strings.EqualFold(assigneeLogin, a.Login()) {
    ids = append(ids, a.ID())
    found = true
    break
    }
    if strings.EqualFold(assigneeLogin, a.DisplayName()) {
    ids = append(ids, a.ID())
    found = true
    break
    }
    }
    if !found {
    return nil, fmt.Errorf("'%s' not found", assigneeLogin)
    }
    }
    return ids, nil
    }

    If we find a match in the first loop for assignableUsers we should not proceed to assignableActors.

  5. linked a pull request that will close this issueAvoid requesting PR reviewer twice #11099on Jun 11, 2025
  6. williammartin commented on Jun 11, 2025

    @williammartin
    Member

    @Mildwhale if you're open to trying out the branch #11099 from source that would be great, but I think this fixes the bug.

  7. Mildwhale commented on Jun 11, 2025

    @Mildwhale
    Author

    @williammartin Sounds good! I'll try out #11099 soon and let you know!

  8. Mildwhale commented on Jun 11, 2025

    @Mildwhale
    Author

    @williammartin Tried out #11099 — looks like the issue's fixed. Thanks a lot for the quick fix!

  9. added
    priority-3Affects a small number of users or is largely cosmetic
    and removed on Jun 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggh-prrelating to the gh pr commandpriority-3Affects a small number of users or is largely cosmetic

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions