Skip to content

Parse Cloud Code Function won't allow Queries, or any object manipulation through cloud code. #7728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
malcolm-dane opened this issue Nov 28, 2021 · 36 comments
Labels
type:question Support or code-level question

Comments

@malcolm-dane
Copy link

New Issue Checklist

Issue Description

Repeated errors in cloud code function using queries. Setting no user in the fields, using master key etc doesn't allow for queries,object manipulation etc. Throws error: Parse error: TypeError: Cannot read property 'protectedFields' of undefined {"code":1,"stack":"Error: TypeError: Cannot read property 'protectedFields' of undefined\n at /app/node_modules/parse-server/lib/Controllers/DatabaseController.js:1170:21\n at processTicksAndRejections (internal/process/task_queues.js:95:5)"}

Steps to reproduce

I had the latest Parse Server, dropped it down to a few months old, and still the bug was there. Create cloud function to Query an Object and return an array etc. Manually created mongoatlas entries and tried to query them via cloud function, these items had no permissions set. master key was set to be used, and user set to false.

Actual Outcome

I have gotten several errors similiar to this or like this one:

error: Parse error: TypeError: Cannot read property 'protectedFields' of undefined {"code":1,"stack":"Error: TypeError: Cannot read property 'protectedFields' of undefined\n at /app/node_modules/parse-server/lib/Controllers/DatabaseController.js:1170:21\n at processTicksAndRejections (internal/process/task_queues.js:95:5)"}

Expected Outcome

For it to atleast return something retrieved from the backend

Environment

Heroku 20
Parse Server 4.10.0 -> latest build.
Updated Node, downgraded node etc. Didn't go too long ago in version numbers.

Server
"parse": "3.4.0",
"parse-server": "4.10.0"

  • Parse Server version: 4.10 but also latest
  • Operating system: `Ubuntu'
  • Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): heroku

Database

  • System (MongoDB or Postgres): atlas
  • Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): Atlas

Client

  • SDK (iOS, Android, JavaScript, PHP, Unity, etc): REST

Logs

error: Parse error: TypeError: Cannot read property 'protectedFields' of undefined {"code":1,"stack":"Error: TypeError: Cannot read property 'protectedFields' of undefined\n at /app/node_modules/parse-server/lib/Controllers/DatabaseController.js:1170:21\

@parse-github-assistant
Copy link

Thanks for opening this issue!

  • 🚀 You can help us to fix this issue faster by opening a pull request with a failing test. See our Contribution Guide for how to make a pull request, or read our New Contributor's Guide if this is your first time contributing.

@mtrezza
Copy link
Member

mtrezza commented Nov 29, 2021

Under "Steps to reproduce" could you please provide a 1. 2. 3. instruction for others to reproduce the issue? And even better, if you could provide a PR with a failing test, it would be even easier to understand.

@mtrezza mtrezza added state:needs-investigation type:bug Impaired feature or lacking behavior that is likely assumed labels Nov 29, 2021
@malcolm-dane
Copy link
Author

I'll do it this weekend. It seems specific to the REST API.

@jonas-db
Copy link

jonas-db commented Dec 22, 2021

I'm experiencing the same error in my jasmine test suite on the latest beta where I start/stop the parse server for every test.. it seems something is not reset/set correctly when the server is reinitialized. The first test always works fine, other tests usually fail with following error. Running each test separate makes all tests pass so it is not a test problem.

[Debug] ParseError: TypeError: Cannot read property 'protectedFields' of undefined
    at /Users/abc/server/node_modules/parse-server/src/Controllers/DatabaseController.js:1337:27
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at Object.getAuthForSessionToken (/Users/abc/server/node_modules/parse-server/src/Auth.js:88:16) {
  code: 1
}

EDIT: adding delay of 5seconds after the parseServer.handleShutdown(); seems to make the tests pass in most cases..

Maybe this is related?: #7525

@mtrezza
Copy link
Member

mtrezza commented Dec 22, 2021

That's interesting, so these are flaky tests? We do have some flaky tests in Parse Server, but it's also not uncommon for all tests to pass. Or are you talking about your own custom tests?

Maybe this is related?: #7525

May well be, depending on the test.

@malcolm-dane
Copy link
Author

malcolm-dane commented Dec 22, 2021 via email

@jonas-db
Copy link

jonas-db commented Dec 23, 2021

I did some further digging.. and these are some observations. What do you think @mtrezza?
(and yes it's my own test suite, based on: #7527 (comment))

in my case the error comes from the fact that:

DatabaseController#filterSensitiveData returns undefined for const perms = schema.getClassLevelPermissions(className); where className is either _Session or _User

const perms = schema.getClassLevelPermissions(className);

Usually this function returns something alike (eg for the _user):

{
  find: { '*': true },
  count: { '*': true },
  get: { '*': true },
  create: { '*': true },
  update: { '*': true },
  delete: { '*': true },
  addField: { '*': true },
  protectedFields: { '*': [ 'email' ] }
}

but since it is now undefined, it triggers an error at the following line:

perms.protectedFields &&

The condition should include && perms because otherwise perms.protectedFields will trigger an error because perms is undefined.

if (!(isUserClass && userId && object.objectId === userId)) {
    protectedFields && protectedFields.forEach(k => delete object[k]); // fields not requested by client (excluded),
    //but were needed to apply protecttedFields

    perms.protectedFields && perms.protectedFields.temporaryKeys && perms.protectedFields.temporaryKeys.forEach(k => delete object[k]);
  }

If I extend the condition as follows:
if (!(isUserClass && userId && object.objectId === userId) && perms) ,
then the test case fails with:

error: Invalid session token {"code":209,"stack":"Error: Invalid session token\n at Object.getAuthForSessionToken (/Users/jonas/git/judica/server/node_modules/parse-server/src/Auth.js:100:11)\n at processTicksAndRejections (internal/process/task_queues.js:97:5)"}

Although my user is created and logged in (they have an id + sessiontoken).. I believe this error is not representative (just like the original error) and the issue lies somewhere in the code path above..

const registration = await Parse.User.signUp(email, "test", attributes); // AS_MASTER
        console.log(">>>> registration")
        console.log(registration.id,registration.get('sessionToken'))
        expect(registration.get('sessionToken')).to.not.be.undefined
        expect(registration.id).to.not.be.undefined

        const user = await Parse.User.logIn(email, "test");
        console.log(">>>> user")
        console.log(user.id,user.get('sessionToken'))
        expect(user.get('sessionToken')).to.not.be.undefined
        expect(user.id).to.not.be.undefined

        return user

So the question remains why schema.getClassLevelPermissions(className); returns undefined in some cases.. and as it occurs randomly it seems like a timing issue...

The SchemaController.schemadata is the following when the error occurs:

SchemaData {
  __data: {},
  __protectedFields: { _User: { '*': [Array] } }
}

but otherwise it is:

SchemaData {
  __data: {
    _User: {
      fields: [Object],
      classLevelPermissions: [Object],
      indexes: [Object]
    }
  },
  __protectedFields: { _User: { '*': [Array] } }
}

I also figured that performInitialization is not implemented for the mongodb adapter, while it is for the postgres adapter (where it ensures some schema things...). Maybe it needs to return a promise that waits for the schemas to be inserted instead of the current Promise.resolve()? Although i'm not sure this is related but performInitialization is called by the ParseServer constructor.

performInitialization(): Promise<void> {

@mtrezza
Copy link
Member

mtrezza commented Dec 23, 2021

Are you only observing this issue in your tests, or in an actual app? The original description by @malcolm-dane did not mention any tests, and they mentioned "It occurs for me in regular use", so I assume it was not test related.

I want to exclude the possibility that this issue is only related to the test setup where a some things are mocked for testing.

@jonas-db
Copy link

jonas-db commented Dec 24, 2021 via email

@jonas-db
Copy link

I've been narrowing down the issue.. but I need to dig some more. Right now it seems to occur when I have an asyncParse.Cloud.afterSave registered. @malcolm-dane do you have such a trigger as well maybe?

@malcolm-dane
Copy link
Author

malcolm-dane commented Dec 24, 2021 via email

@malcolm-dane
Copy link
Author

malcolm-dane commented Dec 24, 2021 via email

@jonas-db
Copy link

jonas-db commented Dec 24, 2021

@malcolm-dane, no i don't have that dependency. But in my case it seems because of aftersave triggers triggering other ones; and maybe i'm not awaiting some async operations correctly.. Still trying to figure it out

EDIT: idk, it might also be that signup/login for different users on nodejs is not supported? i'm clueless

@jonas-db
Copy link

jonas-db commented Dec 26, 2021

EDIT: @mtrezza I found it... the SchemaCache is globally! I needed to clear it before each start of a test with SchemaCache.clear();. This should be documented somewhere

@mtrezza
Copy link
Member

mtrezza commented Dec 27, 2021

Good detective work! That would also mean it (practically) only affects tests, no actual app deployments. Can everyone in this thread who had this issue confirm that?

@malcolm-dane
Copy link
Author

Mine is happening in production, however it may be that I am not initializing correctly. I have a bastardized version of the standard old Heroku version. I haven't tried to troubleshoot this in depth, but I do think it is happening due to a race condition in the async functions.

@malcolm-dane
Copy link
Author

Hey so i went back and hardset the test flag to a negative, ensuring test is false. Interestingly, it's doing something new. See below. I'll have to write some cloud function, this is a different error message than what I had before. I mean my server is serving pages correctly, it's just cloud functions..

2021-12-28T02:00:48.074440+00:00 heroku[router]: at=info method=POST path="/parse/classes/GameScore" host=hackback-apps-gmbh.herokuapp.com request_id=e00dc6c0-9931-44dc-ba03-ecc93f00c8ce fwd="3.215.181.193" dyno=web.1 connect=0ms service=9ms status=500 bytes=685 protocol=https

2021-12-28T02:00:48.073163+00:00 app[web.1]: error: Parse error: TypeError: Cannot read property 'protectedFields' of undefined {"code":1,"stack":"Error: TypeError: Cannot read property 'protectedFields' of undefined\n at /app/node_modules/parse-server/lib/Controllers/DatabaseController.js:1170:21\n at runMicrotasks ()\n at processTicksAndRejections (internal/process/task_queues.js:95:5)"}

2021-12-28T02:00:48.075490+00:00 app[web.1]: (node:22) UnhandledPromiseRejectionWarning: Error: [object Object]

2021-12-28T02:00:48.075493+00:00 app[web.1]: at handleError (/app/node_modules/parse-server/node_modules/parse/lib/node/RESTController.js:422:17)

2021-12-28T02:00:48.075493+00:00 app[web.1]: at runMicrotasks ()

2021-12-28T02:00:48.075494+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_queues.js:95:5)

2021-12-28T02:00:48.075494+00:00 app[web.1]: (Use node --trace-warnings ... to show where the warning was created)

2021-12-28T02:00:48.075531+00:00 app[web.1]: (node:22) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 37)

2021-12-28T02:00:48.075548+00:00 app[web.1]: (node:22) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

@malcolm-dane
Copy link
Author

I changed my config, and that allowed cloud code to run, albeit not correctly. From a Cloud Code Function it seems several features are broken in cloud code if you try and run an operation against the database without a user.

I need to pull the built code of this parse server from Heroku, to see the code referenced in the error codes.From the debugging I have done and searches I have done it seems that Querying the MongoAtlas DB from cloud, regardless of forcing the master key in the function, results in a variety of errors.

When attempted, the function gets rejected.

Reviewing the stock code in DatabaseController.js will help narrow down exactly what the problem is. I had planned to build this from source and run it locally and see if the issue persist or not.

The stock errors are misleading, the errors are thrown even when a catch is implemented. It seems as if query.find({userMasterKey=true}) doesn't do anything. I suspect that it is attempting to read fields in the Object in Atlas, that are not specified, or are presumed permission protected by default or possibly reading the fields either in tandem with the original query or as a first order operation. I think there is a race condition, one cloud function causes two posts in my log. Not sure exactly what to think....

However the functions now run, but not correctly and not when trying to access from the database.

It would be helpful if I could see someone else cloud functions....

@jonas-db
Copy link

jonas-db commented Dec 28, 2021

@malcolm-dane The only advice I can give is to strip down your server configuration to a minimal example. Maybe strip down your GameScore triggers if you have any? Also are you using/loading/migrating schemas on startup? Try disabling that because when I add schemas to the startup config it doesn't work anymore (but that might be related to #7525, i need to investigate more).

@malcolm-dane
Copy link
Author

malcolm-dane commented Dec 28, 2021

@malcolm-dane The only advice I can give is to strip down your server configuration to a minimal example. Maybe strip down your GameScore triggers if you have any? Also are you using/loading/migrating schemas on startup? Try disabling that because when I add schemas to the startup config it doesn't work anymore (but that might be related to #7525, i need to investigate more).

Got it working. With out a schema defined, cloud code can not be triggered server side. It seems that on deployment it generates a schema of it's own, but I'm still not sure where the collision is because it shouldn't matter. I am not sure what is causing this on init, but maybe include in the documentation something like below. As StackExchange, Reddit, etc there is lots of misleading info.

### In case anyone lands on this in the future. Solution is below.

In order for database Operations to properly function in cloud code use the rest API to Post sample below. Enter in your Parse configuration info, and change the web route to the object you are needing to manipulate in the back-end.
Once this schema and access information is saved, cloud functions manipulating the database Object will now work.
If you have a Parse Object in your mongo DB named 'Students', to manipulate via cloud functions a schema delegating access will need to be posted for that Object.
Query -> /parse/classes/Students

Requires

/schemas/Students

curl -X POST \
-H "X-Parse-Application-Id:YOURID" \
-H "X-Parse-MASTER-KEY:YOURKEY" \
-H "Content-Type: application/json" \
-d '{
"classLevelPermissions":
{
"find": {
  "*": true ,
  "*": true
 },
"get": {
  "*":true ,
  "*": true
},
"create": { "*": true  },
"update": { "*": true },
"delete": { "*": true }
}
}' \
https:// https://YOURPARSEAPP.com/parse/schemas/OBJECT_NAME

Errors: error: Parse error: TypeError: Cannot read property 'protectedFields' of undefined {"code":1,"stack":"Error: TypeError: Cannot read property 'protectedFields' of undefined\n at /app/node_modules/parse-server/lib/Controllers/DatabaseController.js:1170:21\n at runMicrotasks ()\n at processTicksAndRejections (internal/process/task_queues.js:95:5)"}

@malcolm-dane
Copy link
Author

Good detective work! That would also mean it (practically) only affects tests, no actual app deployments. Can everyone in this thread who had this issue confirm that?

Can I submit a Parse Server generic version that works right out the box on Heroku to the main project? Parse is my favorite framework for rapid prototyping and I am sure others would love to be able to have a copy of this that works right out of the box in 2021. Let me know!

@mtrezza
Copy link
Member

mtrezza commented Jan 1, 2022

Can I submit a Parse Server generic version that works right out the box on Heroku to the main project?

Not sure I understand what the issue is that you discovered. Is it possible to reproduce this in a failing test or does this only relate to your custom environment?

@malcolm-dane
Copy link
Author

malcolm-dane commented Jan 1, 2022 via email

@mtrezza
Copy link
Member

mtrezza commented Jan 1, 2022

Thanks for clarifying, which changes / steps are needed to make it work on Heroku?
Does this still relate to the issue you originally described here "Parse Cloud Code Function won't allow..."?

@malcolm-dane
Copy link
Author

malcolm-dane commented Jan 1, 2022 via email

@malcolm-dane
Copy link
Author

malcolm-dane commented Jan 1, 2022 via email

@malcolm-dane
Copy link
Author

malcolm-dane commented Jan 16, 2022 via email

@malcolm-dane
Copy link
Author

malcolm-dane commented Jan 16, 2022 via email

@mtrezza
Copy link
Member

mtrezza commented Jan 16, 2022

This seems to be a one-time commit so it's difficult to see what changed to make it work on Heroku. Do you think it's possible to propose the changes to the original parse-server-example repo in the form of a PR? Not sure whether it's mergeable but we could at least discuss. If mergeable, we could avoid having to maintain two separate repos (original and Heroku-compatible).

It seems this issue is originally about something else, so maybe you can open the PR and we can discuss there to not confuse readers of this thread.

@malcolm-dane
Copy link
Author

malcolm-dane commented Jan 16, 2022 via email

@mtrezza
Copy link
Member

mtrezza commented Jan 16, 2022

As you already pointed out, I also think an addition / modification of the original parse-server-example repo would bring the most visibility and advantage for others. For the moment, I think a PR that shows the changes needed in the example repo would be a good start for discussion.

@malcolm-dane
Copy link
Author

Sounds good. Sorry been busy with day job.

@malcolm-dane
Copy link
Author

When doing the pull request, it's master to version that the request is made on right? Sorry, like I said I don't normally participate in open source projects generally.

@mtrezza
Copy link
Member

mtrezza commented Jan 21, 2022

You'd start a new branch off alpha branch in this repo, see #7639.

@Jakub-Plan-d-k
Copy link

I had a similar issue when I was setting up local test environment and github actions test environment.

The reason was connected to the APP_ID. It needs to be the same in server config, Parse.initialize() in main.js and Parse.initialize() in the test setup. In my case, the environment setup was incorrect and therefore the environment variables not passed to the function.

After I ensured it is correctly set everywhere, all worked perfectly.

@mtrezza mtrezza added type:question Support or code-level question and removed type:bug Impaired feature or lacking behavior that is likely assumed labels Apr 19, 2025
@mtrezza
Copy link
Member

mtrezza commented Apr 19, 2025

Closing as this is a years old issue that hasn't been reported otherwise. Presumably a config issue.

@mtrezza mtrezza closed this as completed Apr 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question Support or code-level question
Projects
None yet
Development

No branches or pull requests

4 participants