Skip to content

Fix outdated organization_membership events#560

Merged
mattgd merged 3 commits intomainfrom
md5/fix-for-outdated-organization-membership-events
Feb 20, 2026
Merged

Fix outdated organization_membership events#560
mattgd merged 3 commits intomainfrom
md5/fix-for-outdated-organization-membership-events

Conversation

@mattgd
Copy link
Contributor

@mattgd mattgd commented Feb 20, 2026

Description

This PR addresses handling of custom_attributes in organization membership events. The field is now defaulted to an empty dict and undefined values from the API are coerced to empty dicts, maintaining type safety without requiring optional fields.

A new event test verifies that organization_membership events with null custom_attributes deserialize correctly.

Documentation

Does this require changes to the WorkOS Docs? E.g. the API Reference or code snippets need updates.

  • Yes

Default custom_attributes to empty dict and coerce null values from API to empty dict, ensuring type safety without requiring optional fields. Add event test for null custom_attributes deserialization.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@mattgd mattgd requested a review from a team as a code owner February 20, 2026 15:15
@mattgd mattgd requested a review from alisherry February 20, 2026 15:15
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 20, 2026

Greptile Summary

This PR fixes a deserialization issue where the WorkOS API can return custom_attributes: null in organization membership event payloads, which would cause a Pydantic validation error since the field was typed as Mapping[str, Any] without accepting None.

  • Adds a field_validator on OrganizationMembership.custom_attributes to coerce None values to {} before validation, preventing runtime errors when processing events from the API.
  • Sets the default value of custom_attributes to {}, making the field optional in the input payload while maintaining the non-optional Mapping[str, Any] type for consumers.
  • Adds a targeted test that verifies organization_membership.created events with custom_attributes: None deserialize correctly as {}.

Confidence Score: 5/5

  • This PR is safe to merge — it's a minimal, well-tested fix for a real API deserialization issue.
  • The change is small, focused, and correct. The field_validator properly handles the None case before Pydantic validation, and the default = {} is safe in Pydantic (which copies defaults). The fix is consistent with how the codebase handles similar nullable fields (e.g., Profile.custom_attributes uses Optional, but OrganizationMembership intentionally avoids exposing None to consumers). The new test directly validates the fix. No security, performance, or correctness concerns.
  • No files require special attention

Important Files Changed

Filename Overview
src/workos/types/user_management/organization_membership.py Adds a Pydantic field_validator to coerce null custom_attributes to {} and sets the default value to {}. Clean and correct implementation.
tests/test_events.py Adds a fixture and test for organization membership events with null custom_attributes. Verifies deserialization works correctly and asserts the event type and coerced value.

Sequence Diagram

sequenceDiagram
    participant API as WorkOS API
    participant SDK as Python SDK
    participant Val as field_validator
    participant Model as OrganizationMembership

    API->>SDK: Event payload with custom_attributes: null
    SDK->>Val: _coerce_null_custom_attributes(None)
    Val->>Val: None → {}
    Val->>Model: Validate with custom_attributes = {}
    Model->>SDK: OrganizationMembership(custom_attributes={})
Loading

Last reviewed commit: aa575ec

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

custom_attributes is never null from the API, only undefined. Remove
the field_validator and null test, keep only the default and the
missing-field test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roles: Optional[Sequence[OrganizationMembershipRole]] = None
status: LiteralOrUntyped[OrganizationMembershipStatus]
custom_attributes: Mapping[str, Any]
custom_attributes: Mapping[str, Any] = {}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This handles cases for events from before the IdP attributes in AuthKit release where custom_attributes is undefined.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mattgd mattgd merged commit 0980a79 into main Feb 20, 2026
11 checks passed
@mattgd mattgd deleted the md5/fix-for-outdated-organization-membership-events branch February 20, 2026 15:26
This was referenced Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants