What happened?
Any search request that uses the Repos collection (SearchIssuesRequest, SearchCodeRequest, ...) throws RepositoryFormatException client-side, before any HTTP request is made, when the repository name part starts with a hyphen — even though such names are valid on GitHub and GitHub's Search API accepts the corresponding repo: qualifier.
Repro
var client = new GitHubClient(new ProductHeaderValue("repro"));
var request = new SearchIssuesRequest
{
Repos = new RepositoryCollection { "myorg/-repo-with-leading-hyphen" }
};
// Throws Octokit.RepositoryFormatException before any HTTP call
await client.Search.SearchIssues(request);
Expected: the qualifier repo:myorg/-repo-with-leading-hyphen is sent to the search API.
Actual:
Octokit.RepositoryFormatException: The list of repositories must be formatted as 'owner/name' - these values don't match this rule: myorg/-repo-with-leading-hyphen
Root cause
The validation regex in Octokit/Helpers/StringExtensions.cs#L142:
static readonly Regex nameWithOwner = new Regex("[a-z0-9.-]{1,}/[a-z0-9.-_]{1,}", ...);
In the name part [a-z0-9.-_], the .-_ sequence is not three literal characters — it is a character range from . (0x2E) to _ (0x5F). The literal hyphen - (0x2D) sits just below the range start, so it is not in the class at all. A name whose first character is - therefore cannot match immediately after the /, and IsNameWithOwnerFormat() returns false. (Names with hyphens in the middle still pass only because the regex is unanchored, so the prefix before the first hyphen satisfies {1,}.)
This regressed in #1418 (the fix for #1406, repo names starting with an underscore): appending _ after the previously trailing literal - ([a-z0-9.-] → [a-z0-9.-_]) accidentally turned .- + _ into the .-_ range — fixing leading underscores while silently breaking leading hyphens. As a side effect the accidental range also admits characters that can never appear in a repository name (/, :, ;, <, =, >, ?, @, [, \, ], ^).
GitHub itself is fine with these names
- Repository names starting with
- can be created on github.com; we hit this in production against a real (private) organization repository whose name starts with -, returned by GitHub's own list organization repositories API.
- The server-side search endpoint parses the qualifier without trouble:
GET /search/issues?q=repo:owner/-nonexistent-repo+type:pr returns the standard 422 "The listed users and repositories cannot be searched..." validation response — exactly the same as for any nonexistent repo, not a query-parse error.
Suggested fix
Reorder the class so all three specials are literals — .-_ → _.-:
static readonly Regex nameWithOwner = new Regex("[a-z0-9.-]{1,}/[a-z0-9_.-]{1,}", ...);
A - or . at the class edges and _ mid-class are all literal, so leading-hyphen (and leading-underscore, leading-dot) names validate, and the accidental junk range disappears. I'll open a PR with this change plus unit tests and link it here.
Versions
Octokit.net 14.0.0 (still present on current main); observed on .NET 8 / .NET 10 — platform-independent (pure regex).
Relevant log output
Octokit.RepositoryFormatException: The list of repositories must be formatted as 'owner/name' - these values don't match this rule: <org>/-<repo-name>
at Octokit.SearchIssuesRequest.MergedQualifiers() in /_/Octokit/Models/Request/SearchIssuesRequest.cs:line 399
at Octokit.BaseSearchRequest.get_Parameters() in /_/Octokit/Models/Request/BaseSearchRequest.cs:line 117
at Octokit.SearchClient.SearchIssues(SearchIssuesRequest search) in /_/Octokit/Clients/SearchClient.cs:line 58
Code of Conduct
What happened?
Any search request that uses the
Reposcollection (SearchIssuesRequest,SearchCodeRequest, ...) throwsRepositoryFormatExceptionclient-side, before any HTTP request is made, when the repository name part starts with a hyphen — even though such names are valid on GitHub and GitHub's Search API accepts the correspondingrepo:qualifier.Repro
Expected: the qualifier
repo:myorg/-repo-with-leading-hyphenis sent to the search API.Actual:
Root cause
The validation regex in
Octokit/Helpers/StringExtensions.cs#L142:In the name part
[a-z0-9.-_], the.-_sequence is not three literal characters — it is a character range from.(0x2E) to_(0x5F). The literal hyphen-(0x2D) sits just below the range start, so it is not in the class at all. A name whose first character is-therefore cannot match immediately after the/, andIsNameWithOwnerFormat()returnsfalse. (Names with hyphens in the middle still pass only because the regex is unanchored, so the prefix before the first hyphen satisfies{1,}.)This regressed in #1418 (the fix for #1406, repo names starting with an underscore): appending
_after the previously trailing literal-([a-z0-9.-]→[a-z0-9.-_]) accidentally turned.-+_into the.-_range — fixing leading underscores while silently breaking leading hyphens. As a side effect the accidental range also admits characters that can never appear in a repository name (/,:,;,<,=,>,?,@,[,\,],^).GitHub itself is fine with these names
-can be created on github.com; we hit this in production against a real (private) organization repository whose name starts with-, returned by GitHub's own list organization repositories API.GET /search/issues?q=repo:owner/-nonexistent-repo+type:prreturns the standard422"The listed users and repositories cannot be searched..." validation response — exactly the same as for any nonexistent repo, not a query-parse error.Suggested fix
Reorder the class so all three specials are literals —
.-_→_.-:A
-or.at the class edges and_mid-class are all literal, so leading-hyphen (and leading-underscore, leading-dot) names validate, and the accidental junk range disappears. I'll open a PR with this change plus unit tests and link it here.Versions
Octokit.net 14.0.0 (still present on current
main); observed on .NET 8 / .NET 10 — platform-independent (pure regex).Relevant log output
Code of Conduct