Skip to content

OrganizationMembership::$permissions deserialization fails when API returns null #67

@ohallors

Description

@ohallors

The OrganizationMembership class has a $permissions property typed as a non-nullable array, but the Clerk API sometimes
returns null for this field. This causes a TypeError during deserialization when using the SDK's list organization
memberships endpoint.

Affected Endpoint

GET /users/{user_id}/organization_memberships

Expected Behavior

The SDK should handle null values for the permissions field gracefully, either by:

  1. Making the property nullable (?array)
  2. Defaulting null to an empty array [] during deserialization

Actual Behavior

When the API returns a response like this:

  {                                                                                                                          
    "data": [                                                                                                                
      {                                                                                                                      
        "id": "orgmem_xxx",                                                                                                  
        "organization": { "id": "org_xxx", ... },                                                                            
        "role": "org:admin",                                                                                                 
        "permissions": null,                                                                                                 
        ...                                                                                                                  
      }                                                                                                                      
    ],                                                                                                                       
    ...                                                                                                                      
  }         

The Speakeasy serializer throws a TypeError because it cannot assign null to the non-nullable array property.

Reproduction Steps

  1. Create an organization and add a user as a member
  2. Call the SDK to list the user's organization memberships:

use Clerk\Backend\Models\Operations\ListOrganizationMembershipsRequest;

  $sdk = /* your Clerk SDK instance */;                                                                                      
  $request = new ListOrganizationMembershipsRequest(userId: $userId);                                                        
  $response = $sdk->users->getOrganizationMemberships($request);                                                             
  // TypeError thrown during deserialization                

Workaround

We worked around this by making a direct HTTP call to the API and fixing the JSON before deserializing:

  $rawJson = $response->getBody()->getContents();                                                                            
  $data = json_decode($rawJson, true);                                                                                       
                                                                                                                             
  // Fix null permissions                                                                                                    
  foreach (array_keys($data['data'] ?? []) as $index) {                                                                      
      if (!isset($data['data'][$index]['permissions']) || $data['data'][$index]['permissions'] === null) {                   
          $data['data'][$index]['permissions'] = [];                                                                         
      }                                                                                                                      
  }                                                                                                                          
                                                                                                                             
  $fixedJson = json_encode($data);                                                                                           
                                                                                                                             
  // Now deserialize with SDK's serializer                                                                                   
  $serializer = JSON::createSerializer();                                                                                    
  $memberships = $serializer->deserialize($fixedJson, OrganizationMemberships::class, 'json', ...);     

Suggested Fix

In the OrganizationMembership class (or the OpenAPI spec that generates it), change:

  // From:                                                                                                                   
  public array $permissions;                                                                                                 
                                                                                                                             
  // To either:                                                                                                              
  public ?array $permissions = null;                                                                                         
                                                                                                                             
  // Or with a default:                                                                                                      
  public array $permissions = [];                 

Environment

  • clerk/backend-php: (please check your version)
  • PHP Version: 8.4
  • Speakeasy Serializer: (bundled with SDK)

Impact

This bug prevents reliable detection of existing organization memberships, which can cause:

  • False negatives when checking if a user is already a member
  • Subsequent API calls to add the user fail with "already_a_member_in_organization"
  • Migration/sync workflows to fail unexpectedly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions