Skip to content

Ownership rules widget crashes when name is numeric (team_id) #110588

@sentry-junior

Description

@sentry-junior

Summary

The ownership rules widget breaks when an actor's name field receives a numeric value (team internal ID) instead of a string. This happens because the API response schema uses identifier (e.g. a team slug or user email) renamed to name, but the id field in the schema holds the raw integer DB id — and when avatar/display code receives that integer as name, getInitials() calls name.trim() which fails at runtime since integers don't have .trim().

Root Cause

The GET /api/0/{org}/{project}/ownership/ endpoint calls rename_schema_identifier_for_parsing() which renames identifiername in each owner entry. The schema also includes a numeric id field (set by add_owner_ids_to_schema) — so each owner in the API response looks like:

{ "type": "team", "name": "#my-team", "id": 2251960 }

The frontend types this as Actor ({ id: string, name: string, type }), but the id coming from the backend is a number, not a string. In ownershipRulesTable.tsx, the code does:

const team = TeamStore.getById(owners[0].id);

When TeamStore.getById returns null (e.g. team not in store), the fallback path reaches getInitials(owners[0].name) in useAvatar.ts. At this point, if name somehow resolves to the numeric id value (e.g. due to a type confusion or a missing name field in a specific data path), name.trim() throws because integers have no .trim() method.

Observed in the debugger: name = 2251960 (a number), sanitizedName unavailable, confirming the value passed as name is a team's integer ID.

Additionally, the Actor type on the frontend declares id: string, but the API returns id as a number — this type mismatch may contribute to the bug in downstream identity comparisons.

Reproduction

  1. Set up ownership rules that reference a team.
  2. Open the ownership rules widget for a project in the demo org.
  3. If the team is not loaded in TeamStore (e.g. demo org, stale store), the widget errors rendering the avatar.

Expected Behavior

  • getInitials() should guard against non-string name inputs (e.g. String(name) coercion or early return).
  • The API should ensure id is serialized as a string to match the frontend Actor type, or the frontend should coerce it.
  • TeamStore.getById lookup should handle string/number id mismatch gracefully.

Files

  • src/sentry/issues/endpoints/project_ownership.pyrename_schema_identifier_for_parsing + add_owner_ids_to_schema
  • static/app/components/core/avatar/useAvatar.tsgetInitials() (no type guard)
  • static/app/views/settings/project/projectOwnership/ownershipRulesTable.tsx — owner avatar rendering

Action taken on behalf of Max Kosty.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions