Skip to content

Conversation

@cursor
Copy link
Contributor

@cursor cursor bot commented Nov 19, 2025

Fixes SeerApiError: {"detail":"No run_id found for agent_id..."} by gracefully handling Cursor webhook updates for agents not initiated by Sentry.

Previously, Seer would return a 404 if an agent_id from a Cursor webhook didn't map to an internal Autofix run_id. This caused Sentry to log a SeerApiError (cursor_webhook.seer_update_error) for an expected external agent completion.

This PR modifies update_coding_agent_state to:

  • Detect the specific "No run_id found" 404 response from Seer.
  • Log an informational message (seer.autofix.coding_agent_state_not_registered) and return False in this specific case, rather than raising a SeerApiError.
  • The Cursor webhook handler (_update_coding_agent_status) now logs cursor_webhook.agent_not_registered at an informational level when Seer ignores the update.

This change reduces noise in error tracking by treating these external agent completions as expected informational events instead of errors.

Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.


Open in Cursor Open in Web

Co-authored-by: jenn.muengtaweepongsa <jenn.muengtaweepongsa@sentry.io>
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 19, 2025
This change adds a `run_id` to the webhook URL for coding agent integrations. This allows the webhook handler to associate incoming events with a specific autofix run.

Co-authored-by: jenn.muengtaweepongsa <jenn.muengtaweepongsa@sentry.io>
@codecov
Copy link

codecov bot commented Nov 19, 2025

❌ 8 Tests Failed:

Tests completed Failed Passed Skipped
29875 8 29867 244
View the top 3 failed test(s) by shortest run time
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostTriggerSourceTest::test_root_cause_without_relevant_repos_falls_back_to_request_repos
Stack Traces | 2.4s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:1115: in test_root_cause_without_relevant_repos_falls_back_to_request_repos
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostTriggerSourceTest::test_root_cause_repos_extracted_and_deduped
Stack Traces | 2.46s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:1050: in test_root_cause_repos_extracted_and_deduped
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostLaunchTest::test_launch_with_all_parameters
Stack Traces | 2.56s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:627: in test_launch_with_all_parameters
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostLaunchTest::test_seer_storage_failure_continues
Stack Traces | 2.67s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:925: in test_seer_storage_failure_continues
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostLaunchTest::test_launches_coding_agent
Stack Traces | 2.72s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:584: in test_launches_coding_agent
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostTriggerSourceTest::test_root_cause_trigger_source
Stack Traces | 2.81s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:973: in test_root_cause_trigger_source
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostLaunchTest::test_multi_repo_launch
Stack Traces | 2.91s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:723: in test_multi_repo_launch
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m
tests.sentry.integrations.api.endpoints.test_organization_coding_agents.OrganizationCodingAgentsPostTriggerSourceTest::test_solution_trigger_source
Stack Traces | 4.59s run time
#x1B[1m#x1B[.../api/endpoints/test_organization_coding_agents.py#x1B[0m:1157: in test_solution_trigger_source
    response = self.get_success_response(self.organization.slug, method="post", **data)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:627: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants