Summary
When a user invokes the OpenHands Slack bot in a workspace where the OpenHands GitHub App is installed against a single repo with repository_selection: "selected", the repo picker dropdown shows that repo twice. Picking either entry works correctly — purely cosmetic, but confusing on first use.
Reproduction
- Install the OpenHands GitHub App on a GitHub org with Only select repositories, scoped to a single repo (e.g.
your-org/your-repo).
- Connect that GitHub identity to your OpenHands user.
- From a Slack workspace whose OpenHands install is bound to that user, mention the bot in a thread (e.g.
@OpenHands slack-to-issue).
- When the repo picker renders, click the dropdown.
Expected: one entry — your-org/your-repo.
Actual: two entries, both your-org/your-repo.
Root cause
From the integration pod logs, the dropdown is populated by slack_on_options_load (in server/routes/integration/slack.py → slack.on_options_load). Internally it calls a user-repo search:
GET https://api.github.com/search/repositories?per_page=20&sort=pushed&order=desc&q=in%3Aname++user%3A<login>
The q parameter has an empty token between in:name and user:<login>, producing q=in:name++user:<login>. GitHub rejects this with 422 Unprocessable Entity (logged in repos.search_repositories as WARNING User search failed: ...).
The fallback path then returns the App-installed repos — but without deduplicating against the prepopulated default that's also in the option list. The picker thus renders two entries for the same repo.
Live log evidence (timestamps and IDs redacted):
WARNING repos.search_repositories: User search failed: Unknown error:
Client error '422 Unprocessable Entity' for url
'https://api.github.com/search/repositories?per_page=20&sort=pushed&order=desc&q=in%3Aname++user%3A<login>'
INFO slack.on_options_load: slack_on_options_load_success
search_value="" num_options=2
When the App scope is exactly one repo, this manifests as the duplicate. With multiple repos in scope, the duplicate may still occur for whichever repo also matches the (still-malformed) search.
Suggested fixes (either independently helps)
- Fix the malformed query: drop the empty
in:name token when no search string is provided, or only apply in:name:<term> when term is non-empty. (In repos.search_repositories or wherever the query is composed.)
- Dedup options in
slack_on_options_load before returning to Slack — set-based dedup on (owner, name) would prevent the duplicate even if the query continues 422'ing.
(1) is the upstream root cause; (2) is defense in depth.
Environment
- OpenHands self-hosted via the Replicated VM path (single EC2,
OpenHands-Cloud/terraform/aws/)
- Image: whatever ships in the late-April 2026 Replicated release
Happy to PR a fix if pointed at the right module.
Summary
When a user invokes the OpenHands Slack bot in a workspace where the OpenHands GitHub App is installed against a single repo with
repository_selection: "selected", the repo picker dropdown shows that repo twice. Picking either entry works correctly — purely cosmetic, but confusing on first use.Reproduction
your-org/your-repo).@OpenHands slack-to-issue).Expected: one entry —
your-org/your-repo.Actual: two entries, both
your-org/your-repo.Root cause
From the integration pod logs, the dropdown is populated by
slack_on_options_load(inserver/routes/integration/slack.py→slack.on_options_load). Internally it calls a user-repo search:The
qparameter has an empty token betweenin:nameanduser:<login>, producingq=in:name++user:<login>. GitHub rejects this with422 Unprocessable Entity(logged inrepos.search_repositoriesasWARNING User search failed: ...).The fallback path then returns the App-installed repos — but without deduplicating against the prepopulated default that's also in the option list. The picker thus renders two entries for the same repo.
Live log evidence (timestamps and IDs redacted):
When the App scope is exactly one repo, this manifests as the duplicate. With multiple repos in scope, the duplicate may still occur for whichever repo also matches the (still-malformed) search.
Suggested fixes (either independently helps)
in:nametoken when no search string is provided, or only applyin:name:<term>whentermis non-empty. (Inrepos.search_repositoriesor wherever the query is composed.)slack_on_options_loadbefore returning to Slack — set-based dedup on(owner, name)would prevent the duplicate even if the query continues 422'ing.(1) is the upstream root cause; (2) is defense in depth.
Environment
OpenHands-Cloud/terraform/aws/)Happy to PR a fix if pointed at the right module.