payloadcms/payload · error · Forbidden

You are not allowed to perform this action.

Error message

You are not allowed to perform this action.

What it means

Thrown by the jobs Local API `queue` function (Forbidden, from `req.t`) when `overrideAccess` is not explicitly false AND the configured `jobsConfig.access.queue` returns false. By default that access function returns true only for logged-in users, so anonymous queueing is denied.

Source

Thrown at packages/payload/src/queues/localAPI.ts:122

            ? TTaskOrWorkflowSlug
            : never
        },
  ): Promise<
    TTaskOrWorkflowSlug extends keyof TypedJobs['workflows']
      ? Job<TTaskOrWorkflowSlug>
      : JobFromTask<TTaskOrWorkflowSlug>
  > => {
    const overrideAccess = args?.overrideAccess !== false
    const req: PayloadRequest = args.req ?? (await createLocalReq({}, payload))

    if (!overrideAccess) {
      /**
       * By default, jobsConfig.access.queue will be `defaultAccess` which is a function that returns `true` if the user is logged in.
       */
      const accessFn = payload.config.jobs?.access?.queue ?? (() => true)
      const hasAccess = await accessFn({ req })
      if (!hasAccess) {
        throw new Forbidden(req.t)
      }
    }

    let queue: string | undefined = undefined

    // If user specifies queue, use that
    if (args.queue) {
      queue = args.queue
    } else if (args.workflow) {
      // Otherwise, if there is a workflow specified, and it has a default queue to use,
      // use that
      const workflow = payload.config.jobs?.workflows?.find(({ slug }) => slug === args.workflow)
      if (workflow?.queue) {
        queue = workflow.queue
      }
    }

    const data: Partial<Job> = {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Authenticate the request before queueing so the default access passes.
  2. Broaden `jobsConfig.access.queue` to allow the intended caller (e.g. service accounts).
  3. For trusted internal calls, pass `overrideAccess: true` explicitly.

Example fix

// before
await payload.jobs.queue({ workflow: 'email', data, req })

// after
// trusted internal path
await payload.jobs.queue({ workflow: 'email', data, req, overrideAccess: true })
Defensive patterns

Strategy: validation

Validate before calling

if (!req.user && args?.overrideAccess !== true) {
  // default access.queue returns Boolean(user); queue will be Forbidden
  throw new Error('queue requires an authenticated user or overrideAccess: true')
}

await payload.jobs.queue({ workflow, data, req, overrideAccess: trusted })

Type guard

import type { PayloadRequest, User } from 'payload'

function isAuthenticated(req: PayloadRequest): req is PayloadRequest & { user: User } {
  return Boolean(req.user)
}

if (!isAuthenticated(req) && !trusted) throw new Error('auth required to queue')

Try / catch

try {
  await payload.jobs.queue({ workflow, data, req })
} catch (err) {
  if (err.statusCode === 403) {
    // authenticate, broaden access.queue, or pass overrideAccess: true
  } else throw err
}

Prevention

When it happens

Trigger: Calling `payload.jobs.queue({ workflow, data, req })` with a request whose `access.queue` returns false — typically because `req.user` is absent (default access = `Boolean(user)`), or a custom access function denies the user.

Common situations: Queueing a job from a public/anonymous endpoint without auth; a custom `jobs.access.queue` that is too restrictive; using a server `req` that was never authenticated.

Related errors


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