parse-server
parse-server copied to clipboard
Add optional objectId to Parse.Error if possible
New Feature / Enhancement Checklist
- [x] I am not disclosing a vulnerability.
- [x] I am not just asking a question.
- [x] I have searched through existing issues.
Current Limitation
I came across an issue when using the ParseSwift framework. When using the saveAll() function, it's impossible to identify the object where the error occurred.
Feature / Enhancement Description
I would suggest to add an optional objectId to the error response coming from the server. This could then be decoded in the ParseSwift framework and can be used by developers to identify the failing object.
Example Use Case
I would change the current class Error
to this:
I might need some help with implementing the constructor on the specific locations where it would be necessary.
class Error {
static OTHER_CAUSE: ErrorCode.OTHER_CAUSE;
static INTERNAL_SERVER_ERROR: ErrorCode.INTERNAL_SERVER_ERROR;
static CONNECTION_FAILED: ErrorCode.CONNECTION_FAILED;
static OBJECT_NOT_FOUND: ErrorCode.OBJECT_NOT_FOUND;
static INVALID_QUERY: ErrorCode.INVALID_QUERY;
static INVALID_CLASS_NAME: ErrorCode.INVALID_CLASS_NAME;
static MISSING_OBJECT_ID: ErrorCode.MISSING_OBJECT_ID;
static INVALID_KEY_NAME: ErrorCode.INVALID_KEY_NAME;
static INVALID_POINTER: ErrorCode.INVALID_POINTER;
static INVALID_JSON: ErrorCode.INVALID_JSON;
static COMMAND_UNAVAILABLE: ErrorCode.COMMAND_UNAVAILABLE;
static NOT_INITIALIZED: ErrorCode.NOT_INITIALIZED;
static INCORRECT_TYPE: ErrorCode.INCORRECT_TYPE;
static INVALID_CHANNEL_NAME: ErrorCode.INVALID_CHANNEL_NAME;
static PUSH_MISCONFIGURED: ErrorCode.PUSH_MISCONFIGURED;
static OBJECT_TOO_LARGE: ErrorCode.OBJECT_TOO_LARGE;
static OPERATION_FORBIDDEN: ErrorCode.OPERATION_FORBIDDEN;
static CACHE_MISS: ErrorCode.CACHE_MISS;
static INVALID_NESTED_KEY: ErrorCode.INVALID_NESTED_KEY;
static INVALID_FILE_NAME: ErrorCode.INVALID_FILE_NAME;
static INVALID_ACL: ErrorCode.INVALID_ACL;
static TIMEOUT: ErrorCode.TIMEOUT;
static INVALID_EMAIL_ADDRESS: ErrorCode.INVALID_EMAIL_ADDRESS;
static MISSING_CONTENT_TYPE: ErrorCode.MISSING_CONTENT_TYPE;
static MISSING_CONTENT_LENGTH: ErrorCode.MISSING_CONTENT_LENGTH;
static INVALID_CONTENT_LENGTH: ErrorCode.INVALID_CONTENT_LENGTH;
static FILE_TOO_LARGE: ErrorCode.FILE_TOO_LARGE;
static FILE_SAVE_ERROR: ErrorCode.FILE_SAVE_ERROR;
static DUPLICATE_VALUE: ErrorCode.DUPLICATE_VALUE;
static INVALID_ROLE_NAME: ErrorCode.INVALID_ROLE_NAME;
static EXCEEDED_QUOTA: ErrorCode.EXCEEDED_QUOTA;
static SCRIPT_FAILED: ErrorCode.SCRIPT_FAILED;
static VALIDATION_ERROR: ErrorCode.VALIDATION_ERROR;
static INVALID_IMAGE_DATA: ErrorCode.INVALID_IMAGE_DATA;
static UNSAVED_FILE_ERROR: ErrorCode.UNSAVED_FILE_ERROR;
static INVALID_PUSH_TIME_ERROR: ErrorCode.INVALID_PUSH_TIME_ERROR;
static FILE_DELETE_ERROR: ErrorCode.FILE_DELETE_ERROR;
static REQUEST_LIMIT_EXCEEDED: ErrorCode.REQUEST_LIMIT_EXCEEDED;
static INVALID_EVENT_NAME: ErrorCode.INVALID_EVENT_NAME;
static USERNAME_MISSING: ErrorCode.USERNAME_MISSING;
static PASSWORD_MISSING: ErrorCode.PASSWORD_MISSING;
static USERNAME_TAKEN: ErrorCode.USERNAME_TAKEN;
static EMAIL_TAKEN: ErrorCode.EMAIL_TAKEN;
static EMAIL_MISSING: ErrorCode.EMAIL_MISSING;
static EMAIL_NOT_FOUND: ErrorCode.EMAIL_NOT_FOUND;
static SESSION_MISSING: ErrorCode.SESSION_MISSING;
static MUST_CREATE_USER_THROUGH_SIGNUP: ErrorCode.MUST_CREATE_USER_THROUGH_SIGNUP;
static ACCOUNT_ALREADY_LINKED: ErrorCode.ACCOUNT_ALREADY_LINKED;
static INVALID_SESSION_TOKEN: ErrorCode.INVALID_SESSION_TOKEN;
static LINKED_ID_MISSING: ErrorCode.LINKED_ID_MISSING;
static INVALID_LINKED_SESSION: ErrorCode.INVALID_LINKED_SESSION;
static UNSUPPORTED_SERVICE: ErrorCode.UNSUPPORTED_SERVICE;
static AGGREGATE_ERROR: ErrorCode.AGGREGATE_ERROR;
static FILE_READ_ERROR: ErrorCode.FILE_READ_ERROR;
static X_DOMAIN_REQUEST: ErrorCode.X_DOMAIN_REQUEST;
code: ErrorCode;
message: string;
objectId: string;
constructor(code: ErrorCode, message: string, objectId: string = null);
}
Alternatives / Workarounds
There are none
3rd Party References
n/a
Thanks for opening this issue!
- 🎉 We are excited about your ideas for improvement!
There is a pending PR to refactor the error messages. Maybe it helps to merge that first?
There is a pending PR to refactor the error messages. Maybe it helps to merge that first?
I just looked into the open PR, but it doesn't seem to add an objectId, am I right? I might be wrong, I'm not super familiar with server-side code.
I think you are right. I was more referring to maybe merging that one first so it doesn't have to be refactored, because it's a large PR. But depends on how many changes your PR intends to make - if not so many yours could be merged independently.
Regarding your suggested change:
- At first glance this seems to be too specific of a use case to me. What if there is a batch operation in which n of N objects fail - then this already becomes unusable because that info cannot be transmitted.
What are the current workarounds and why are they not a viable alternative?
- A developer can manipulate individual objects in parallel to see which one failed.
- If the manipulation happens in Cloud Code, a custom parsable JSON error can be returned with whatever info the use case requires.
- Instead of adding a new param objectId to the error we could simply mention the objectId in the error message; it wouldn't be automatically parsable but for manual debugging it could be enough.
I'm curious to hear more about your intentions for this change and why the workarounds are not sufficient.
- Instead of adding a new param objectId to the error we could simply mention the objectId in the error message; it wouldn't be automatically parsable but for manual debugging it could be enough.
This could actually be enough for me. But I find it strange that no one else runs into this problem. At the moment I'm having an error where an object from a batch operation failed to save, but I am unable to see which object it is...
So this could fix it.
The other question is whether we should add object data to logs. That never sounds like a good idea, because an object ID is then exposed in the logs. Since we allow custom object IDs, we cannot anticipate what information is used and what grade of confidentiality that information has.
A better solution seems to be sending a list of failed object IDs in the response, so that information is ephemeral and contained. I'm unsure about the syntax in which that should be returned though.
The other question is whether we should add object data to logs. That never sounds like a good idea, because an object ID is then exposed in the logs. Since we allow custom object IDs, we cannot anticipate what information is used and what grade of confidentiality that information has.
That's a very good point!
A better solution seems to be sending a list of failed object IDs in the response, so that information is ephemeral and contained. I'm unsure about the syntax in which that should be returned though.
That could fix it
Do you have any suggestion regarding the syntax to return the results?
A workaround could be to use enableExpressErrorHander
with:
app.use((err, req, res, next) => {
let httpStatus;
switch (err.code) {
case Parse.Error.INTERNAL_SERVER_ERROR:
httpStatus = 500;
break;
case Parse.Error.OBJECT_NOT_FOUND:
httpStatus = 404;
break;
default:
httpStatus = 400;
}
res.status(httpStatus);
let error = err.message;
let objectId = req.originalUrl.split('/').at(-1);
res.json({ code: err.code, error, objectId });
});
A workaround could be to use
enableExpressErrorHander
with:app.use((err, req, res, next) => { let httpStatus; switch (err.code) { case Parse.Error.INTERNAL_SERVER_ERROR: httpStatus = 500; break; case Parse.Error.OBJECT_NOT_FOUND: httpStatus = 404; break; default: httpStatus = 400; } res.status(httpStatus); let error = err.message; let objectId = req.originalUrl.split('/').at(-1); res.json({ code: err.code, error, objectId }); });
Where should I put this script? I know I need to set enableExpressErrorHander
to true
in ParseServerOptions.