Skip to content

Invalid UUID in equals filter is treated as IS NULL #16479

@tobiasvdorp

Description

@tobiasvdorp

Describe the Bug

Invalid UUID values in an equals filter appear to be sanitized to null, which then changes the meaning of the query to IS NULL.

We noticed this with a UUID relationship field, but this may affect UUID columns more generally.

In our case:

  • equals: "<valid UUID with matching documents>" returns the correct documents.
  • equals: "<valid UUID with no matching documents>" returns an empty docs array.
  • equals: "invalid-something" returns documents where the relationship field is null.

We are not fully sure what the intended behavior should be. Possible expected behavior could be:

  • Throw a query validation error because "invalid-something" is not a valid UUID.
  • Return no results, matching the behavior of a valid UUID that simply does not match anything.

But returning documents where the field is null seems unexpected, because the caller asked for equals: "invalid-something", not equals: null.

This may be related to the UUID sanitization added in #8369.

In @payloadcms/drizzle, sanitizeQueryValue appears to convert invalid UUID strings to null:

if (isUUID && typeof formattedValue === 'string') {
  if (!uuidValidate(val)) {
    formattedValue = null
  }
}

Then later in parseParams, equals with a null query value is interpreted as IS NULL:

if (operator === 'equals' && queryValue === null) {
  constraints.push(isNull(resolvedColumn))
  break
}

So the effective query becomes "column is null".

There also seems to be a related issue when multiple operators are provided on the same field. If equals is processed first and becomes IS NULL, the break means another operator like exists: true may not be applied.

Link to the code that reproduces this issue

https://github.com/tobiasvdorp/payload-uuid-treated-as-null-issue-repro

Reproduction Steps

  1. Create a collection with a relationship field:
{
  name: 'articleType',
  type: 'relationship',
  relationTo: 'article-types',
  hasMany: false,
}
  1. Configure Postgres with UUID ids:
postgresAdapter({
  idType: 'uuid',
})
  1. Create at least one document where the relationship field is empty (null).

  2. Query with a syntactically valid UUID that has no matching documents. This returns an empty docs array as expected:

query {
  Articles(
    where: {
      articleType: {
        equals: "valid-article-type-uuid" // replace with actual UUID of existing articleType
      }
    }
  ) {
    docs {
      id
      articleType {
        id
      }
    }
  }
}
  1. Query with a value that is not a valid UUID:
query {
  Articles(
    where: {
      articleType: {
        equals: "invalid-something"
      }
    }
  ) {
    docs {
      id
      articleType {
        id
      }
    }
  }
}
  1. Observe that the query returns documents where articleType is null.

  2. Optionally add exists: true on the same field:

query {
  Articles(
    where: {
      articleType: {
        equals: "invalid-something"
        exists: true
      }
    }
  ) {
    docs {
      id
      articleType {
        id
      }
    }
  }
}
  1. Observe that this does not appear to prevent the null relationship documents from being returned in our case.

Which area(s) are affected?

db: postgres, area: core

Environment Info

Binaries:
  Node: 22.17.1
  npm: 10.9.2
  Yarn: N/A
  pnpm: 10.33.0
Relevant Packages:
  payload: 3.82.1
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:15 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T6000
  Available memory (MB): 32768
  Available CPU cores: 10

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions