From bf769d17447aba684ee7aa13f607bcd7d21e9eef Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Wed, 4 Mar 2026 15:50:37 -0500 Subject: [PATCH] Handle deleted GitHub issues (410 error) gracefully (#13217) Co-authored-by: openhands --- .../github/github_v1_callback_processor.py | 33 ++++++++++++------- .../test_github_v1_callback_processor.py | 28 ++++++++++++++++ 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/enterprise/integrations/github/github_v1_callback_processor.py b/enterprise/integrations/github/github_v1_callback_processor.py index 541cb27377..42e68027ca 100644 --- a/enterprise/integrations/github/github_v1_callback_processor.py +++ b/enterprise/integrations/github/github_v1_callback_processor.py @@ -3,7 +3,7 @@ from typing import Any from uuid import UUID import httpx -from github import Auth, Github, GithubIntegration +from github import Auth, Github, GithubException, GithubIntegration from integrations.utils import get_summary_instruction from integrations.v1_utils import handle_callback_error from pydantic import Field @@ -132,19 +132,30 @@ class GithubV1CallbackProcessor(EventCallbackProcessor): full_repo_name = self.github_view_data['full_repo_name'] issue_number = self.github_view_data['issue_number'] - if self.inline_pr_comment: + try: + if self.inline_pr_comment: + with Github(auth=Auth.Token(installation_token)) as github_client: + repo = github_client.get_repo(full_repo_name) + pr = repo.get_pull(issue_number) + pr.create_review_comment_reply( + comment_id=self.github_view_data.get('comment_id', ''), + body=summary, + ) + return + with Github(auth=Auth.Token(installation_token)) as github_client: repo = github_client.get_repo(full_repo_name) - pr = repo.get_pull(issue_number) - pr.create_review_comment_reply( - comment_id=self.github_view_data.get('comment_id', ''), body=summary + issue = repo.get_issue(number=issue_number) + issue.create_comment(summary) + except GithubException as e: + if e.status == 410: + _logger.info( + '[GitHub V1] Issue/PR %s#%s was deleted, skipping summary post', + full_repo_name, + issue_number, ) - return - - with Github(auth=Auth.Token(installation_token)) as github_client: - repo = github_client.get_repo(full_repo_name) - issue = repo.get_issue(number=issue_number) - issue.create_comment(summary) + else: + raise # ------------------------------------------------------------------------- # Agent / sandbox helpers diff --git a/enterprise/tests/unit/integrations/github/test_github_v1_callback_processor.py b/enterprise/tests/unit/integrations/github/test_github_v1_callback_processor.py index 36ada82fe8..4e8e500318 100644 --- a/enterprise/tests/unit/integrations/github/test_github_v1_callback_processor.py +++ b/enterprise/tests/unit/integrations/github/test_github_v1_callback_processor.py @@ -15,6 +15,7 @@ from uuid import uuid4 import httpx import pytest +from github import GithubException from integrations.github.github_v1_callback_processor import ( GithubV1CallbackProcessor, ) @@ -734,6 +735,33 @@ class TestGithubV1CallbackProcessor: with pytest.raises(RuntimeError, match='Missing GitHub credentials'): await github_callback_processor._post_summary_to_github('Test summary') + @patch('integrations.github.github_v1_callback_processor.Auth') + @patch('integrations.github.github_v1_callback_processor.Github') + async def test_post_summary_to_github_deleted_issue_does_not_raise( + self, mock_github, mock_auth, github_callback_processor + ): + """Test that 410 errors (deleted issues) are handled gracefully without raising.""" + mock_github_client = MagicMock() + mock_repo = MagicMock() + mock_repo.get_issue.side_effect = GithubException( + status=410, + data={'message': 'This issue was deleted'}, + headers={}, + ) + mock_github_client.get_repo.return_value = mock_repo + mock_github.return_value.__enter__.return_value = mock_github_client + + mock_token_auth = MagicMock() + mock_auth.Token.return_value = mock_token_auth + + with patch.object( + github_callback_processor, + '_get_installation_access_token', + return_value='test_token', + ): + # Should not raise - 410 errors are handled gracefully + await github_callback_processor._post_summary_to_github('Test summary') + @patch( 'integrations.github.github_v1_callback_processor.GITHUB_APP_CLIENT_ID', 'test_client_id',