parse-community / parse-community/parse-server

Relation query with a null operand throws an uncaught TypeError (500)

Open
#10,637 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
21.4k
Forks
4.8k
Avg merge
7h 45m
Merged PRs (30d)
11

Description

New Issue Checklist

Filed publicly rather than through the security policy: this is an unhandled exception on malformed input, not a disclosure or an authentication problem. The stack trace stays in the server log, the client gets a generic 500, and the process survives, so it is a per-request failure rather than a crash.

Issue Description

reduceInRelation reads .objectId off each constraint operand without checking that the operand is an object. A null anywhere in a relation query constraint therefore raises an uncaught TypeError and the request fails with a generic 500.

Four call sites dereference unguarded (src/Controllers/DatabaseController.js, at the 9.10.1-alpha.6 tree):

if (constraintKey === 'objectId') {
  relatedIds = [query[key].objectId];                     // :1096
} else if (constraintKey == '$in') {
  relatedIds = query[key]['$in'].map(r => r.objectId);    // :1098
} else if (constraintKey == '$nin') {
  isNegation = true;
  relatedIds = query[key]['$nin'].map(r => r.objectId);   // :1101
} else if (constraintKey == '$ne') {
  isNegation = true;
  relatedIds = [query[key]['$ne'].objectId];              // :1104
}

A non-object operand that is not null, for example {"$in": [7]}, is harmless: (7).objectId is undefined, which contributes no id. Only null throws, because it cannot be boxed.

This is reachable with the application id alone. No master key, session token or client key is required.

Related: #4742 reported the same shape in the same function ($in given a non-array, so .map is not a function) and was closed in 2018. The operands here are still unvalidated.

Steps to reproduce
  1. Create a class Owner with a Relation field named friends, and save one object so the field is in the schema.
  2. Send a query whose relation constraint contains a null:
GET /parse/classes/Owner?where={"friends":{"$in":[null]}}
X-Parse-Application-Id: <appId>

Each of these reproduces it:

Constraint Result
{"friends":{"$in":[null]}} 500
{"friends":{"$nin":[null]}} 500
{"friends":{"$ne":null,"$in":[]}} 500
{"friends":{"$ne":null,"$nin":[]}} 500
{"friends":{"$ne":null}} 200, empty results

The last row does not throw because a bare falsy $ne fails the gate at :1084-1090, which requires one of $in, $ne, $nin to be truthy, so the extraction loop never runs. Adding any truthy sibling operator satisfies the gate and the falsy $ne is then dereferenced. An empty array is enough, since [] is truthy.

Actual Outcome
500 {"code":1,"message":"Internal server error."}
Expected Outcome

Either Parse.Error.INVALID_JSON, or the null treated the way every other operand without an objectId is already treated: it yields undefined and contributes no related id, so the constraint resolves to no owners. The second matches the existing behavior for {"$in":[7]} and for {"$in":[{"foo":1}]}, which both return an empty result rather than an error.

Environment

Server

  • Parse Server version: 9.10.1-alpha.6 (ca75b1fed69921f7843dc20b921d9b02dc352626)
  • Operating system: macOS 26.5.2
  • Local or remote host: local

Database

  • System (MongoDB or Postgres): MongoDB
  • Database version: 7.0.25
  • Local or remote host: local

Client

  • SDK (iOS, Android, JavaScript, PHP, Unity, etc): REST
  • SDK version: n/a

The Postgres adapter was not tested.

Logs
TypeError: Cannot read properties of null (reading 'objectId')
    at .../lib/Controllers/DatabaseController.js:946:45
    at Array.map (<anonymous>)
    at .../lib/Controllers/DatabaseController.js:934:43
    at Array.map (<anonymous>)
    at DatabaseController.reduceInRelation (.../lib/Controllers/DatabaseController.js:923:42)
    at .../lib/Controllers/DatabaseController.js:1215:238
    at async _UnsafeRestQuery.runFind (.../lib/RestQuery.js:785:19)

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 at reduceInRelation in src/Controllers/DatabaseController.js and reproduce the REST query using a null operand in $in, $nin, or $ne. Trace the related stack path in lib/Controllers/DatabaseController.js; done means null no longer causes an uncaught TypeError or generic 500, while existing non-object operand behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, mongodb
Domain
api, backend, databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.