Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Regression: `findByID` with `disableErrors: true` throws `NotFound` for null/empty ids since 3.91.0

Open Beginner friendly
#18,935 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@Krrishkumar125 is already working on this.

Since Oct 21, 2026.

  • #18956 by @Krrishkumar125 — open

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Domain
api, backend

Research direction

Read the findByID implementation changed in commit #18000 and trace where the invalid-ID guard handles disableErrors. Reproduce the null-ID case from the issue, then check null, undefined, and empty-string IDs. Done means each returns null with disableErrors: true, while invalid IDs still raise NotFound when it is false.

Written by the indexing model from the issue text.

Description

area: core Bug invalid-reproduction status: needs-triage v3
Describe the Bug

Since 3.91.0, payload.findByID() throws NotFound when the id is null, undefined or "", even with disableErrors: true. In 3.90.2 the same call returned null.

The docs describe disableErrors as "When set to true, errors will not be thrown. Instead, the findByID operation will return null." That no longer holds for invalid ids.

The change came in with #18000 ("check draft read access against the latest version in findByID", 9106bf8). The release notes don't mention it as a behavior change. That commit replaced this guard:

if (!findOneArgs.where?.and?.[0]?.id) {
  throw new NotFound(t)
}

with an explicit id check that runs before the database query:

const isValidID =
  (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && Number.isFinite(id))

if (!isValidID) {
  throw new NotFound(t)
}

The old guard never fired for a null id. where.and[0].id is the { equals: null } object, which is truthy, so the query ran, found nothing, and disableErrors turned that into null. The new guard does fire, and it runs before disableErrors is consulted.

Impact: a common pattern for resolving optional upload fields in server components started throwing after a minor upgrade:

const media = await payload.findByID({
  collection: 'media',
  id: block.backgroundImage, // null when the field is empty
  disableErrors: true,
})

The NotFound propagates as a Server Components render error, so in production every page with an empty upload field returns a 500.

Suggested fix: honor disableErrors in the new guard:

if (!isValidID) {
  if (disableErrors) {
    return null
  }
  throw new NotFound(t)
}
Link to the code that reproduces this issue

https://gist.github.com/mtolmacs/beb3fdc491ee346557a973a6672f1837

Reproduction Steps
  1. Create a blank app with npx create-payload-app@latest and set payload to 3.91.0.
  2. Run this from a server component, route handler or script:
    const payload = await getPayload({ config })
    const result = await payload.findByID({
      collection: 'media',
      id: null as unknown as number,
      disableErrors: true,
    })
    console.log(result)
    
  3. Expected (and what 3.90.2 does): logs null.
    Actual: throws NotFound: Not Found (status 404).

The same happens with id: undefined and id: ''.

Which area(s) are affected?

area: core

Environment Info
Binaries:
  Node: 24.15.0
  npm: 11.12.1
  Yarn: N/A
  pnpm: 11.24.0
Relevant Packages:
  payload: 3.91.0
  next: 16.3.8
  @payloadcms/db-postgres: 3.91.0
  @payloadcms/db-sqlite: 3.91.0
  @payloadcms/drizzle: 3.91.0
  @payloadcms/email-nodemailer: 3.91.0
  @payloadcms/email-resend: 3.91.0
  @payloadcms/graphql: 3.91.0
  @payloadcms/live-preview: 3.91.0
  @payloadcms/live-preview-react: 3.91.0
  @payloadcms/next/utilities: 3.91.0
  @payloadcms/plugin-cloud-storage: 3.91.0
  @payloadcms/plugin-import-export: 3.91.0
  @payloadcms/plugin-redirects: 3.91.0
  @payloadcms/plugin-seo: 3.91.0
  @payloadcms/richtext-lexical: 3.91.0
  @payloadcms/storage-vercel-blob: 3.91.0
  @payloadcms/translations: 3.91.0
  @payloadcms/ui/shared: 3.91.0
  react: 19.2.4
  react-dom: 19.2.4
Dominant language
TypeScript
Stars
45.5k
Forks
4.3k
Avg merge
1d 19h
Merged PRs (30d)
299

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

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.

More from payloadcms/payload

All issues in payloadcms/payload

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.