payloadcms / payloadcms/payload

Invalid UUID in treated as IS NULL and returns incorrect data

Open
#16,483 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: core area: graphql db: mongodb db: postgres stale status: needs-triage v3
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

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?

area: graphql, area: core, db: postgres, db: mongodb

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with sanitizeQueryValue in @payloadcms/drizzle and follow parseParams, comparing invalid UUID handling with equals and exists. Use the linked reproduction to verify behavior for PostgreSQL and MongoDB, then confirm the intended outcome for invalid UUIDs and ensure the result no longer treats them as IS NULL.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, mongodb, postgresql, typescript
Domain
api, backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.