Skip to content

gh search does not properly handle multi-word search query terms #11228

Description

@annettejanewilson

Describe the bug

When using gh search prs with --limit 1000, the request fails with the error message "Invalid search query The search is longer than 256 characters."

It appears that internally, an extra layer of escaping is applied every for every subsequent page of results, until the search string becomes so long that it is rejected by the server.

Affected version

gh version 2.74.2 (2025-06-17)
https://github.com/cli/cli/releases/tag/v2.74.2

Steps to reproduce the behavior

Run:

gh search prs 'bump client' --created=='>=2024-06-11' --match title --limit 1000 --json 'title,url,state'

Observe

Invalid search query "\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"bump client\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\"\\\"\" created:=>=2024-06-11 in:title".
The search is longer than 256 characters.

and an exit code of 1.

Expected vs actual behavior

The expected behaviour is that a short query that succeeds for --limit 30 should not result in "Invalid search query" with --limit 1000.

Logs

$ GH_DEBUG=1 gh search prs 'bump client' --created=='>=2024-06-11' --match title --limit 1000 --json 'title,url,state'
* Request at 2025-07-04 09:44:31.069311 +0100 BST m=+0.102011834
* Request to https://api.github.com/repos/cli/cli/releases/latest
⣾* Request at 2025-07-04 09:44:31.117253 +0100 BST m=+0.149953709
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=1&per_page=100&q=%22bump+client%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⣻* Request took 269.649792ms
⢿* Request took 1.37664225s
⡿* Request at 2025-07-04 09:44:32.620046 +0100 BST m=+1.652743918
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=2&per_page=100&q=%22%5C%22bump+client%5C%22%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⣯* Request took 1.14711725s
* Request at 2025-07-04 09:44:33.856533 +0100 BST m=+2.889227501
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=3&per_page=100&q=%22%5C%22%5C%5C%5C%22bump+client%5C%5C%5C%22%5C%22%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⣾* Request took 1.192825125s
⣽* Request at 2025-07-04 09:44:35.116841 +0100 BST m=+4.149533084
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=4&per_page=100&q=%22%5C%22%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22bump+client%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%22%5C%22%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⣻* Request took 1.144724167s
⢿* Request at 2025-07-04 09:44:36.343849 +0100 BST m=+5.376538126
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=5&per_page=100&q=%22%5C%22%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22bump+client%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%22%5C%22%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⣯* Request took 1.386538667s
⣷* Request at 2025-07-04 09:44:37.813457 +0100 BST m=+6.846143126
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=6&per_page=100&q=%22%5C%22%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22bump+client%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%22%5C%22%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⢿* Request took 1.434989792s
* Request at 2025-07-04 09:44:39.311696 +0100 BST m=+8.344378168
* Request to https://github.skyscannertools.net/api/v3/search/issues?page=7&per_page=100&q=%22%5C%22%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22bump+client%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%5C%5C%5C%5C%22%5C%5C%5C%22%5C%22%22+created%3A%3D%3E%3D2024-06-11+in%3Atitle+type%3Apr
⡿* Request took 58.694791ms
Invalid search query "\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"bump client\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\"\\\"\" created:=>=2024-06-11 in:title type:pr".
The search is longer than 256 characters.

As can be seen, every subsequent request made to the search has multiplied the size of the previous request. They consist primarly of backslashes. It's unclear whether they are actually performing the intended search.

Activity

  1. deleted a comment from on Jul 7, 2025
  2. babakks commented on Jul 7, 2025

    @babakks
    Member

    Thanks for this catch, @annettejanewilson! 🙏

    Looked into this, and I can confirm there is an annoying bug here. As a bit of context, gh tends to surround multi-word query args with double quotes before submitting an API request:

    cli/pkg/search/query.go

    Lines 133 to 138 in 1cbfbf8

    func quote(s string) string {
    if strings.ContainsAny(s, " \"\t\r\n") {
    return fmt.Sprintf("%q", s)
    }
    return s
    }

    This is all fine, except that the changes (i.e. quoted values) replace the original state, and then the same quoting happens when gh is fetching the next page. As you can see in the snippet below, argument passed to the ks parameter is changed after the function returns:

    cli/pkg/search/query.go

    Lines 151 to 161 in 1cbfbf8

    func formatKeywords(ks []string) []string {
    for i, k := range ks {
    before, after, found := strings.Cut(k, ":")
    if !found {
    ks[i] = quote(k)
    } else {
    ks[i] = fmt.Sprintf("%s:%s", before, quote(after))
    }
    }
    return ks
    }

    As a result of this argument mutation, the query grows and worse that, it changes into a different query. Therefore, the returned result is not exactly what the user was looking for (except for the first page, though).

    Thanks again for reporting this issue, @annettejanewilson! I'm going to put down the A/C for this in the next comment.

  3. added
    priority-2Affects more than a few users but doesn't prevent core functions
    coreThis issue is not accepting PRs from outside contributors
    gh-searchrelating to the gh search command
    and removed on Jul 7, 2025
  4. andyfeller commented on Jul 7, 2025

    @andyfeller
    Contributor

    Adding a note that this is would be a problem for any gh search command where --limit exceeds the 100 results per page limit of the REST Search endpoints used. Essentially, a search query with a multi-word search term with --limit over 100 could be impacted by this.

  5. babakks commented on Jul 7, 2025

    @babakks
    Member

    As mentioned in the above comment, we should the unwanted argument mutation in formatKeywords, and return a new slice from the function.

    Acceptance Criteria

    Given I have a query that contains a whitespace character, and my query will result in several pages of pagination
    When I run the gh search command (for any subcommand)
    Then my query should complete without error

    Note to reviewers: you can also validate the change by setting GH_DEBUG=1 and seeing that the query isn’t exponentially increasing in length.

  6. changed the title [-]"The search is longer than 256 characters" when setting high --limit[/-] [+]`gh search` does not properly handle multi-word search query terms[/+] on Jul 7, 2025
  7. self-assigned this
    on Jul 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreThis issue is not accepting PRs from outside contributorsgh-searchrelating to the gh search commandpriority-2Affects more than a few users but doesn't prevent core functions

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions