Skip to content

Conversation

@seer-by-sentry
Copy link
Contributor

Fixes JAVASCRIPT-35TZ. The issue was that: User serialization failure returns null, which OrganizationMemberSerializer fails to handle, propagating null members to frontend.

  • Ensure that None values resulting from serialization failures are skipped in OrganizationMemberSerializer.
  • Update Serializer.serialize_many to use the walrus operator to assign the serialization result and filter out any None results before returning the list.

This fix was generated by Seer in Sentry, triggered by Ryan Albrecht. 👁️ Run ID: 7873449

Not quite right? Click here to continue debugging with Seer.

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.

@seer-by-sentry seer-by-sentry bot requested a review from ryan953 December 23, 2025 14:25
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Dec 23, 2025
@ryan953 ryan953 marked this pull request as ready for review December 23, 2025 14:28
@ryan953 ryan953 added the Trigger: getsentry tests Once code is reviewed: apply label to PR to trigger getsentry tests label Dec 23, 2025

with sentry_sdk.start_span(op="serialize.iterate", name=type(serializer).__name__):
return [serializer(o, attrs=attrs.get(o, {}), user=user, **kwargs) for o in objects]
return [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Index out of bounds when serializing single object fails

When serialize() is called with a single object, it wraps it in a list, recursively calls itself, and then accesses [0] on the result. With the new filtering logic that removes None results, if that single object's serialization fails and returns None, the returned list will be empty, causing an IndexError at line 55.

Additional Locations (1)

Fix in Cursor Fix in Web

Comment on lines +48 to 51
if u is None:
continue
# Filter out the emails from the user data
u.pop("emails", None)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Filtering None values in Serializer.serialize_many() can cause an IndexError in downstream code that accesses list elements by index, such as in dashboard.py.
Severity: HIGH | Confidence: High

🔍 Detailed Analysis

The change in Serializer.serialize_many() filters out None values from its results. Previously, if a user serialization failed, the list would contain a None element. Now, the list will be empty in that scenario. Downstream code in dashboard.py directly accesses the first element of the returned list using [0]. When the new change causes an empty list to be returned, this direct access will raise an IndexError: list index out of range, causing a crash when a dashboard operation requests a user that fails to serialize.

💡 Suggested Fix

Instead of filtering out None values, which changes the length of the returned list, consider propagating them. Alternatively, update all call sites that rely on list indexing, like the one in dashboard.py, to handle cases where the list might be empty. For example, check the list's length before accessing an index.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/sentry/api/serializers/models/organization_member/base.py#L48-L51

Potential issue: The change in `Serializer.serialize_many()` filters out `None` values
from its results. Previously, if a user serialization failed, the list would contain a
`None` element. Now, the list will be empty in that scenario. Downstream code in
`dashboard.py` directly accesses the first element of the returned list using `[0]`.
When the new change causes an empty list to be returned, this direct access will raise
an `IndexError: list index out of range`, causing a crash when a dashboard operation
requests a user that fails to serialize.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 7873747

@ryan953 ryan953 requested a review from a team December 23, 2025 14:31
@codecov
Copy link

codecov bot commented Dec 23, 2025

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
28073 3 28070 227
View the top 3 failed test(s) by shortest run time
tests.sentry.api.serializers.test_base.BaseSerializerTest::test_child_serializer_failure
Stack Traces | 0.109s run time
#x1B[1m#x1B[.../api/serializers/test_base.py#x1B[0m:78: in test_child_serializer_failure
    result = serialize(foo, serializer=ParentSerializer())
#x1B[1m#x1B[.../api/serializers/base.py#x1B[0m:55: in serialize
    return serialize([objects], user=user, serializer=serializer, **kwargs)[0]
#x1B[1m#x1B[31mE   IndexError: list index out of range#x1B[0m
tests.sentry.api.serializers.test_base.BaseSerializerTest::test_serialize
Stack Traces | 0.263s run time
#x1B[1m#x1B[.../api/serializers/test_base.py#x1B[0m:60: in test_serialize
    assert len(rv) == 2
#x1B[1m#x1B[31mE   AssertionError: assert 1 == 2#x1B[0m
#x1B[1m#x1B[31mE    +  where 1 = len([{'avatar': {'avatarType': 'letter_avatar', 'avatarUrl': None, 'avatarUuid': None}, 'avatarUrl': 'https://gravatar.com...2, 23, 14, 30, 31, 18247, tzinfo=datetime.timezone.utc), 'email': '[email protected]', ...}])#x1B[0m
tests.sentry.dashboards.endpoints.test_organization_dashboard_details.OrganizationDashboardDetailsGetTest::test_dashboard_viewable_with_no_edit_permissions
Stack Traces | 2.84s run time
#x1B[1m#x1B[.../dashboards/endpoints/test_organization_dashboard_details.py#x1B[0m:387: in test_dashboard_viewable_with_no_edit_permissions
    assert response.status_code == 200, response.content
#x1B[1m#x1B[31mE   AssertionError: b'{"detail":"Internal Error","errorId":null}'#x1B[0m
#x1B[1m#x1B[31mE   assert 500 == 200#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.

@billyvg
Copy link
Member

billyvg commented Dec 23, 2025

We should probably figure out the root cause i.e. why serialization is failing

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 Trigger: getsentry tests Once code is reviewed: apply label to PR to trigger getsentry tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants