payloadcms/payload · error · NotFound

Not Found

Error message

Not Found

What it means

Reading a global where the access-control `read` policy returned `false` (and `disableErrors` is not set). Payload throws `NotFound` rather than `Forbidden` when access is denied for a global read, so the API does not leak the existence of a global the caller cannot see.

Source

Thrown at packages/payload/src/globals/operations/findOne.ts:100

      }
    }

    // /////////////////////////////////////
    // Retrieve and execute access
    // /////////////////////////////////////

    let accessResult!: AccessResult

    if (!overrideAccess) {
      accessResult = await executeAccess(
        { slug: globalConfig.slug, disableErrors, req },
        globalConfig.access.read,
      )
    }

    if (accessResult === false) {
      if (!disableErrors) {
        throw new NotFound(req.t)
      }
      return null!
    }

    const select = sanitizeSelect({
      fields: globalConfig.flattenedFields,
      select: resolveSelect({
        config: globalConfig.select,
        operation: 'read',
        req,
        select: incomingSelect,
      }),
    })

    // /////////////////////////////////////
    // Perform database operation
    // /////////////////////////////////////

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Ensure the caller is authenticated and has read access per `globalConfig.access.read`.
  2. If calling server-side where access is already authorized, pass `overrideAccess: true`.
  3. Adjust the access function to allow the intended audience, or call with `disableErrors: true` to receive `null` instead of a throw.

Example fix

// before (unauthenticated read of restricted global)
await payload.findGlobal({ slug: 'settings', req })
// after (authenticate the user)
await payload.findGlobal({ slug: 'settings', req: authenticatedReq })
// or server-side trusted call
await payload.findGlobal({ slug: 'settings', req, overrideAccess: true })
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling, gate on access yourself (server) or check auth state (client)
function canReadGlobal(user, globalAccessRead) {
  if (!globalAccessRead) return true // no policy
  return Boolean(globalAccessRead({ req: { user } }))
}
if (!canReadGlobal(req.user, globalConfig.access?.read)) {
  // skip the call, render 'unavailable', or authenticate
}

Type guard

function isNotFound(err: any): err is { name: 'NotFound'; statusCode: number } {
  return err?.name === 'NotFound' || err?.statusCode === 404
}

Try / catch

try {
  const g = await payload.findGlobal({ slug: 'settings', req })
  return g
} catch (err) {
  if (err?.name === 'NotFound' || err?.statusCode === 404) {
    // access denied or truly absent — treat as unavailable to the caller
    return null
  }
  throw err
}

Prevention

When it happens

Trigger: Calling `payload.findGlobal({ slug, req })` (or the REST `GET /api/globals/<slug>`) as a user whose `access.read` returns `false`; calling from an unauthenticated request on a members-only global.

Common situations: Logged-out user hitting a restricted global; role-based read access that excludes the current user; front-end fetching a global before the session is established.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/62c4c2d701b30128. Report an issue: GitHub.