docs

GitHub

Create GitHub issues from Unhandled issues or link existing ones, and resolve the Unhandled issue when the GitHub issue closes.

The GitHub integration turns an Unhandled issue into a GitHub issue in the right repository, or links one that already exists. When the GitHub issue is closed, Unhandled resolves its issue for you. It connects through a GitHub App installation, so access is limited to the repositories you grant and nobody's personal token is involved.

Connect

You need to be an organization admin.

  1. Open the organization's Integrations settings (/o/:org/settings/integrations) and click Connect next to GitHub.
  2. GitHub opens the Unhandled app's installation page. Pick the account and the repositories it may access, then install.
  3. GitHub asks you to authorize the Unhandled app, unless you already did. Unhandled uses that authorization once, to check that GitHub lists the installation for your GitHub account and that you own the account it is installed on or are an admin of that organization.
  4. GitHub sends you back to the Integrations page, where GitHub shows Connected with the account name.

The connect link carries an encrypted state that expires after 10 minutes, works once, and only completes for the admin who started it in the same browser session. Collaborators who can only see some of the installation's repositories cannot connect it.

Map repositories

Click Configure next to GitHub and pick one repository per project. The list shows up to 100 repositories the installation can reach. A project's repository is where its new GitHub issues are created and where Link existing searches. To change the repositories the app can see, edit the installation on GitHub.

Create a GitHub issue

On an issue, open the menu and choose Create or link GitHub issue, then Create new. The title starts as the issue title and can be edited. The body is filled in for you:

**TypeError**: Cannot read properties of undefined (reading 'total')

- Application: Shop
- Environments: production
- First seen: 2026-10-19T08:12:44.000Z
- Last seen: 2026-10-21T14:03:10.000Z

[View in Unhandled](https://unhandled.example.com/o/acme/projects/shop/issues/412)

Unhandled sets no labels, assignees or milestone. If the project has no mapped repository, creation fails with "Link a repository to this project first".

Choose Link existing instead. Search runs is:issue in the project's mapped repository and shows up to 20 results with their state. You can also type a reference as owner/repo#number. A reference to the mapped repository works for anyone who can see the project. A reference to any other repository the installation can access needs an organization admin; for everyone else, linking fails with "Only an admin can use a repository other than the one linked to this project". The same rule applies to creating and linking through the API and the MCP server. Linking is recorded in the issue's activity, and Unlink in the same menu removes it. The link_issue tool of the MCP server also accepts a full GitHub issue URL.

Closing resolves the issue

Unhandled listens to the app's webhooks:

  • When a linked GitHub issue is closed, Unhandled resolves the issue, if it is open or archived for a limited time, and records "resolved externally" in its activity.
  • When it is reopened, Unhandled updates the link's state but leaves the issue as it is.
  • When the app is uninstalled on GitHub, Unhandled removes the GitHub connection.

Nothing flows the other way: resolving in Unhandled does not close the GitHub issue, and Unhandled never comments on it. If the exception happens again after the issue was resolved, it regresses as usual.

Disconnect

Disconnect on the Integrations page removes the connection. Project mappings and existing links are kept for when you connect again. Uninstall the app on GitHub too if you want to revoke its repository access.

Self-hosting

Create a GitHub App for your Unhandled server and set these environment variables:

VariableValue
GITHUB_APP_SLUGThe app's URL slug, used for https://github.com/apps/<slug>/installations/new
GITHUB_APP_IDThe app ID
GITHUB_APP_PRIVATE_KEYThe app's PEM private key; \n sequences are turned into newlines
GITHUB_APP_WEBHOOK_SECRETThe app's webhook secret
GITHUB_APP_CLIENT_IDThe app's client ID (not the app ID)
GITHUB_APP_CLIENT_SECRETA client secret generated in the app settings

In the app settings:

  • Set the setup URL to https://unhandled.example.com/integrations/github/callback, so GitHub returns installation_id and state there after installation.
  • Add the same address as a callback URL. Unhandled sends the admin through GitHub's user authorization to that address. Leave Request user authorization (OAuth) during installation off, since Unhandled starts that step itself.
  • Set the webhook URL to https://unhandled.example.com/webhooks/github. Unhandled verifies the x-hub-signature-256 header and acts on issues events with the closed and reopened actions and on installation events with the deleted action.
  • Grant read and write access to issues, since Unhandled creates, reads and searches them.
  • Grant read access to the organization's members, so Unhandled can check that the admin who connects an organization installation is an admin of that GitHub organization.