While testing DocumentDb stored procedures I intentionally created a document with a duplicate id so that I can observe the DocumentClientException. According to the documentation at http://azure.github.io/azure-documentdb-js-server/Collection.html#.ErrorCodes I was expecting the exception to have a 409 status code indicating Conflict.
The stored procedure code is as follows:
isAccepted = collection.createDocument(collectionLink,
duplicateIdDoc,
{ disableAutomaticIdGeneration: true },
function(err, createdDoc, options){
if (err) throw err; // Rollback
});
I do receive an exception but the error code is 400 (BadRequest). The message text indicates the correct problem. A resource with the specified id or name already exists.
"Message: {\"Errors\":[\"Encountered exception while executing function. Exception = Error: {\\"Errors\\":[\\"Resource with specified id or name already exists\\"]}\r\nStack trace: Error: {\\"Errors\\":[\\"Resource with specified id or name already exists\\"]}\n at Anonymous function (duplicateIdTest.js:56:26)\n at Anonymous function (duplicateIdTest.js:685:29)\"]}\r\nActivityId: 886230cf-8d49-433e-845f-8cc7c2ae486d, Request URI: /apps/514defcb-ac21-44e6-a8e0-c7b785523c6c/services/32782613-7101-4924-97b0-604052a6723b/partitions/be6c2ec8-130c-4596-90a2-b1807977dd0b/replicas/131240065159522367p"
Am I missing something? Thanks.
All errors thrown inside stored procedures are propagated as 400 (BadRequest). However, individual calls to the database like createDocument return the same error codes as the REST API.
For example, you can check the value of err.code === 409 inside your callback to validate that crateDocument failed due to a conflict. amd not something else.
err.code wouldn't work, Use err.number in your callback to handle known exception
Ex: err.number === 409 for conflict
Related
I am not sure if I am just doing something wrong or if this is actually not working. I want to display the original publication error on the client, in case I catched one:
Meteor.publish('somePub', function (args) {
const self = this
try {
// ... publication logic
catch (pubErr) {
self.error(pubErr)
}
})
On the client I am "catching" this error via the onStop callback:
Meteor.subscribe('somePub', args, {
onStop: function (e) {
// display e to user
}
})
However, while on the server the pubErr is a Meteor.Error and according to the documentation it should be sent to the client, the client just receives a generic sanitized error message:
on the server
{
stack: "useful stack of actual method calls",
error: "somePub.failed",
reason: "somePub.invalidArguments",
details: { arg: undefined }
}
on the client
{
stack: "long list of ddp-message calls",
isClientSafe: true,
error: 500,
reason: "Internal server error",
details: undefined,
message: "Internal server error [500]",
errorType: "Meteor.Error"
}
Note: I also tried to add the error to itself as sanitizedError field, as in the documentation mentioned, but no success either.
Am I missing something here?
Actually I found the answer to the issue after being pointed into the right direction.
The example code works fine on a new project, so I checked why not in my project and I found, that I did not surround the arguments validation using SimpleSchema by the try/catch (unfortunately my question was poorly designed as it missed this important fact, mainly because I abstracted away the schema validation from the publication creation):
Meteor.publish('somePub', function (args) {
pubSchema.validate(args) // throws on fail
const self = this
try {
// ... publication logic
catch (pubErr) {
self.error(pubErr)
}
})
So I thought this could not be the issue's source but here is the thing: Simple Schema is not a pure Meteor package but a NPM package and won't throw a Meteor.Error but a custom instance of Error, that actually has the same attributes (error, errorType, details) like a Meteor.Error, see this part of the source code of a validation context.
So in order to pass the correct information of a SimpleSchema validation error to the client you should
wrap it in a try/catch
add the isClientSafe flag to it
alternatively convert it to a Meteor.Error
Attach a custom Meteor.Error as sanitizedError property to it
Since upgrading to meteor 1.8.0.2 from 1.6.x I've noticed that any method call that results in an error is printed on the server console as:
Exception while invoking method 'login' [object Object]
Exception while invoking method 'customMethodByMe' [object Object]
This happens both on development on my mac and deployed on Galaxy.
Before, the whole stack trace was printed, but this Object object logging doesnt help me figure out the actual problem. My solution so far has been to wrap method implementation in a try catch statement that logs the original exception and rethrows it for the client to know.
Meteor.methods({
'customMethodByMe'() {
try {
return customMethodByMeImpl();
} catch (e) {
console.log(e)
throw e;
}
}
});
In this case, since the error is on the login method which is in a package, I cannot update it to print the real problem. On the client, all I get on any error is that there was a 500 error on the server, so no root cause either.
{"isClientSafe":true,"error":500,"reason":"Internal server error","message":"Internal server error [500]","errorType":"Meteor.Error"}
Any ideas on how to temporarly solve this? I've been searching for a server level error handler but so far have found nothing.
thanks
I did not get to experience this directly, but when I need to print an object, I usually use JSON.stringfy.
Meteor.methods({
'customMethodByMe'() {
try {
return customMethodByMeImpl();
} catch (e) {
console.log(JSON.stringify(e));
throw e;
}
}
});
This should resolve so that you can at least read the error log.
I am getting an Exception whenever a user logged in into his account, and I cant see the collection data until the page is been refreshed… **[but I am not getting any exception if I use it like
Books.find({“customer_name”:this.userId);
instead of
Books.find({“customer_name”:Meteor.user().emails[0].address);
and I don't need that step because in my app users collection finding should be based on their email id, not by userId…]**
my code is shown below :
Someone, please help me out:frowning_face:
server - main.js:
var My_collection;
Meteor.publish(‘books’, function() {
My_collection =
Books.find({“customer_name”:Meteor.user().emails[0].address);
return My_collection;
client -main.js:
Template.viewBooks.helpers({
books() {
return Books.find({}, { sort: { books_order: -1 } }).fetch();
},
});
client - main.html
{{#each books}}
{{books_id}}
{{/each}}
ERROR:
App running at: http://localhost:3000/ I20171205-16:06:49.773(5.5)?
Exception from sub transactions id wQ9DpjjABEiPzMZ9P TypeError: Cannot
read property ‘emails’ of null I20171205-16:06:49.872(5.5)? at
Subscription._handler (server/main.js:16:75)
I20171205-16:06:49.873(5.5)? at maybeAuditArgumentChecks
(packages/ddp-server/livedata_server.js:1768:12)
I20171205-16:06:49.873(5.5)? at
DDP.CurrentPublicationInvocation.withValue
(packages/ddp-server/livedata_server.js:1043:15)
I20171205-16:06:49.873(5.5)? at
Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1134:15)
I20171205-16:06:49.873(5.5)? at Subscription.runHandler
(packages/ddp-server/livedata_server.js:1041:51)
I20171205-16:06:49.873(5.5)? at
packages/ddp-server/livedata_server.js:826:41
I20171205-16:06:49.874(5.5)? at Function..each..forEach
(packages/underscore.js:147:22) I20171205-16:06:49.874(5.5)? at
packages/ddp-server/livedata_server.js:822:9
I20171205-16:06:49.874(5.5)? at
Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1134:15)
I20171205-16:06:49.874(5.5)? at Session._setUserId
(packages/ddp-server/livedata_server.js:816:34)
It’s generally bad practice to use Meteor.user() on the server. Without having enough information surrounding how you’re publishing and subscribing to your collections, and since you’re saying you aren’t getting any errors when you use this.userId, you can find the email address the following way:
var currentUser = Meteor.users.findOne(this.userId);
var userEmail = currentUser.emails[0].address;
Then use it in Books.find
If you can provide more information about the subscription and the publication, i’d be able to help out more
I am working with the Facebook graph API and have run into trouble regarding handling failed requests.
I use this code to create a new post
SocialFacebook.createPosting = function(data) {
var options = {
params: {
access_token : data.tokens.accessToken,
message : data.text
}
};
var url = 'https://graph.facebook.com/' + data.graphId + '/feed';
var response = HTTP.call('POST', url, options).data;
return response;
}
But instead of returning a JS object with error information in the response, it throws an error on failed requests
Exception while invoking method 'createPosting' Error: failed [500] {"error":{"message":"Duplicate status message","type":"FacebookApiException","code":506,"error_subcode":1455006,"is_transient":false,"error_user_title":"Duplicate Status Update","error_user_msg":"This status update is identical to the last one you posted. Try posting something different, or delete your previous update."}}
Because it's wrapped in an Error, the otherwise JSON object is now a string with some other stuff appended to it, which makes it difficult to parse and extract the attributes
Any idea as to why it throws an error, instead of returning a JS object with error details like usually?
Much appreciated
According to the docs, about HTTP.call():
On the server, this function can be run either synchronously or asynchronously. If the callback is omitted, it runs synchronously and the results are returned once the request completes successfully. If the request was not successful, an error is thrown.
So there you have it: since you called HTTP.call() synchronously (without providing a callback), if it responds with an error (in your case, Code 500) the error is thrown and not included in the data.
In Meteor.publish, what is a difference between using this.error and simply throwing an Meteor.Error?
this.error is only available inside the publish method. Per the docs:
Stops this client's subscription, triggering a call on the client to the onError callback passed to Meteor.subscribe, if any. If error is not a Meteor.Error, it will be mapped to Meteor.Error(500, "Internal server error").
Throwing a Meteor.Error would not stop the client's subscription, it would just terminate execution and raise the exception. So if you want to ensure Meteor will clean up after you and allow you to handle the error on the client when something unexpected happens, it's recommended to use this.error rather than throwing your own inside the publish method.
It seems they are the same. In the source code:
try {
var res = self._handler.apply(self, EJSON.clone(self._params));
} catch (e) {
self.error(e);
return;
}
So if there is an exception thrown, error is called anyway. error also stops the subscription.