parse-server
parse-server copied to clipboard
Parse.Object.save throws wrong "101 Object not found." error
New Issue Checklist
- Report security issues confidentially.
- Any contribution is under this license.
- Before posting search existing issues.
Issue Description
Parse.Object.save throws "Object not found.", code 101 error when trying to save an existing object with the session token of a user that does not have write permissions on that object.
Steps to reproduce
Fetch a valid object that can be read by everyone, using a query.
const query = ...;
const result = await query.first();
log(result.get("key")); // Will show a valid value here since the user has read permission.
Set any value on the object and try to save it using the session token of a user who does not have write access for the object.
result.set("key", 1);
await result.save(null, { sessionToken: "valid_session_token_without_write_access" });
// Throws a 101 error because the user does not have write permission. The error code should probably be a different one though.
Actual Outcome
101: OBJECT_NOT_FOUND error is thrown.
Expected Outcome
Other error should be thrown:
- 209: INVALID_SESSION_TOKEN
- 119: OPERATION_FORBIDDEN
- Other new error code...
Environment
Tested on the versions mentioned below only.
Server
- Parse Server version:
8.0.0 - Operating system:
Ubuntu - Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc):
Self Hosted Remote
Database
- System (MongoDB or Postgres):
MongoDB - Database version:
7.0.14 - Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc):
Self Hosted Remote
Client
- SDK (iOS, Android, JavaScript, PHP, Unity, etc):
JavaScript - SDK version:
6.0.0
🚀 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.
Seems the correct error code to me, if the session token is valid and the user has neither read nor write permission. The point is that without read permission, it shouldn't even be revealed that the object exists, so "not found" makes sense. If the user had read permission but no write permission, it may be debatable whether the response should be "not found", or a more specific "op forbidden". In fact "not found" could be confusing as an error, but it's unlikely to cause any significant inconvenience compared to a more specific "op forbidden" error code. Please explain why you think that error code was incorrect.
@mtrezza but in this case the user has read permissions, it only lacks write permission. That's why query.first/find actually returns the object and you can inspect it, all values are there. I agree on the severity with you. It mainly causes inconvenience, nothing major in most cases.
PS: I've edited the sample code a bit, to hopefully make it more clear regarding the actual permissions.
I think we could probably change it. Otherwise there would be an additional query needed to differentiate between whether the object really does not exist or only the write permission are missing.
The question is what's needed to change the error. If the auth logic requires a broader restructuring then it may not be worth the hassle.
Do we have an existing error code you'd suggest?
I think 119 - OPERATION_FORBIDDEN would be the correct one.
In fact, this is the error thrown if we run the same code, but restrict write access from CLP instead of ACL.
Good point. Since this is a breaking change, we won't change this until December 2025. But if you'd like to open a PR and add a test case, that'd be welcome.
I haven't figured out yet where the error code is dispatched from. I think it's from the server, not the JS SDK, that's I opened the issue here. But if I figure it out I'll open the PR.
It's most likely the server. If you need to get this feature earlier for your use case, we could merge this immediately instead of waiting until Dec 2025. But since it's a breaking change, we'd need to introduce a temporary Parse Server option to toggle between old and new behavior. That's easy to implement, and we do that sometimes, but it's just some extra effort.