-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Open
Labels
Description
Payload CMS UUID Relationship Validation Issue
Summary
Payload CMS v3 does not properly handle UUID primary keys in relationship field validation. When creating a link with a UUID campaign ID, Payload's relationship validation converts the UUID string to a number (e.g., 5441d413-9eb8-4f22-adf6-29a0c8cc38df becomes 5441), causing validation to fail.
Environment
- Payload CMS Version: 3.x
- Database: PostgreSQL
- Adapter:
@payloadcms/db-postgres - Node Version: 25.2.1
Steps to Reproduce
- Configure a collection with UUID primary key:
export const Campaigns: CollectionConfig = {
slug: 'campaigns',
// ... other config
hooks: {
beforeChange: [
async ({ data, operation }) => {
if (operation === 'create' && !data.id) {
data.id = generateUUID(); // Generate UUID
}
return data;
},
],
},
};- Configure another collection with a relationship to the UUID collection:
export const Links: CollectionConfig = {
slug: 'links',
fields: [
{
name: 'campaign',
type: 'relationship',
relationTo: 'campaigns',
required: true,
},
],
};- Create a campaign (works correctly):
const campaign = await payload.create({
collection: 'campaigns',
data: { name: 'Test Campaign', slug: 'test' },
});
// campaign.id = "5441d413-9eb8-4f22-adf6-29a0c8cc38df" ✅- Try to create a link with the campaign UUID:
const link = await payload.create({
collection: 'links',
data: {
destinationUrl: 'https://example.com',
campaign: '5441d413-9eb8-4f22-adf6-29a0c8cc38df', // UUID string
},
});Expected Behavior
Link should be created successfully with the UUID campaign ID.
Actual Behavior
Validation error occurs:
Error: The following field is invalid: Campaign
Validation errors:
- general: This relationship field has the following invalid relationships: 5441d413-9eb8-4f22-adf6-29a0c8cc38df 0
The error shows Payload is trying to query with params: 5441 instead of the full UUID, indicating it's converting the UUID to a number.
Database Schema
The database schema is correct:
CREATE TABLE campaigns (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- ... other fields
);
CREATE TABLE links (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
campaign_id UUID NOT NULL REFERENCES campaigns(id),
-- ... other fields
);Workarounds Attempted
- Custom validation function: Returns
trueto bypass validation, but Payload's built-in validation still runs - beforeChange hook validation: Validates relationship manually, but Payload's validation runs first
- overrideAccess flag: Used in hooks, but doesn't affect relationship validation
- Direct database queries: Works, but bypasses Payload entirely
Impact
- High: Blocks core functionality (creating links with UUID campaign relationships)
- Affects: Any collection with UUID primary keys that are referenced by relationship fields
- Workaround: Use direct database operations or revert to integer IDs
Related Issues
- GitHub Discussion #4163 - Relationship fields managed as many-to-many
- GitHub Issue #4383 - Validation errors in afterChange hooks
Additional Context
- UUIDs are stored correctly in the database
- READ operations work correctly with UUIDs
- UPDATE operations work correctly with UUIDs
- Only CREATE operations with relationship fields fail
- The issue is specific to Payload's relationship validation, not database operations
Proposed Solution
Payload should:
- Detect when a relationship field references a collection with UUID primary keys
- Use string comparison instead of numeric conversion for UUID validation
- Support UUID primary keys in relationship validation queries
References
- ADR 005: UUID Implementation Strategy - Our decision to revert UUIDs for Payload collections
- UUID Migration Plan - Original migration plan