payloadcms / payloadcms/payload

REST API returns inconsistent query parameter types in req depending on endpoint

Open
#15,224 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Describe the Bug

When making requests to different REST API endpoints, query parameters are parsed into the req object with inconsistent types. The same query parameter can appear as different types (e.g. string vs number) depending on which endpoint handles the request.

In this example you can see that we have two request:

  1. /api/query-param-types?limit=10&draft=true

req.query.limit is a type of number
req.query.draft is a type of boolean

  1. /api/query-param-types/1?limit=10&draft=true

req.query.limit is a type of string
req.query.draft is a type of string

Image

This check is happening in the read access control in a collection:

const readAccess: Access = ({ req }) => {
  if ('limit' in req.query) {
    req.payload.logger.info(`Limit Type: ${typeof req.query.limit}`)
  }
  if ('draft' in req.query) {
    req.payload.logger.info(`Draft Type: ${typeof req.query.draft}`)
  }
  return true
}

Expected Behavior

Query parameter values should be handled consistently across all REST API endpoints. All query parameters should either be returned as strings, or they should be reliably cast to their correct data types (such as numbers and booleans).

Link to the code that reproduces this issue

https://bitbucket.org/clearlinkit/payloadcms-issues/src/master/src/issues/query-param-type-mismatch/QueryParamTypes.ts

Reproduction Steps
  1. Add the following read access control to a collection:
const readAccess: Access = ({ req }) => {
  if ('limit' in req.query) {
    req.payload.logger.info(`Limit Type: ${typeof req.query.limit}`)
  }
  if ('draft' in req.query) {
    req.payload.logger.info(`Draft Type: ${typeof req.query.draft}`)
  }
  return true
}
  1. Start the Payload server
  2. Make a request to the collection root endpoint with query parameters
    /api/{collection}?limit=10&draft=true
  3. Observe the server logs:
    req.query.limit is logged as type number
    req.query.draft is logged as type boolean
  4. Make a request to a single document endpoint in the same collection using identical query parameters:
    /api/{collection}/{id}?limit=10&draft=true
  5. Observe the server logs:
    req.query.limit is logged as type string
    req.query.draft is logged as type string
Which area(s) are affected?

area: core

Environment Info
Binaries:
  Node: 20.11.0
  npm: 10.2.4
  Yarn: 1.22.22
  pnpm: 10.6.4
Relevant Packages:
  payload: 3.70.0
  next: 15.4.10
  @payloadcms/db-postgres: 3.70.0
  @payloadcms/drizzle: 3.70.0
  @payloadcms/graphql: 3.70.0
  @payloadcms/next/utilities: 3.70.0
  @payloadcms/richtext-lexical: 3.70.0
  @payloadcms/translations: 3.70.0
  @payloadcms/ui/shared: 3.70.0
  react: 19.2.1
  react-dom: 19.2.1
Operating System:
  Platform: darwin
  Arch: arm64

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 the reproduction in QueryParamTypes.ts and compare query handling for the collection root and single-document REST endpoints, using the read access control as the observation point. Trace where req.query is populated for each entry point; done means identical query parameter types are reported for both requests, with regression coverage for the reproduced cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.