{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/orleans/issues/1378","repository_url":"https://api.github.com/repos/dotnet/orleans","labels_url":"https://api.github.com/repos/dotnet/orleans/issues/1378/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/orleans/issues/1378/comments","events_url":"https://api.github.com/repos/dotnet/orleans/issues/1378/events","html_url":"https://github.com/dotnet/orleans/issues/1378","id":131685517,"number":1378,"title":"Transparently propagate exceptions to callers without modification","user":{"login":"jdom","id":1361686,"avatar_url":"https://avatars.githubusercontent.com/u/1361686?v=3","gravatar_id":"","url":"https://api.github.com/users/jdom","html_url":"https://github.com/jdom","followers_url":"https://api.github.com/users/jdom/followers","following_url":"https://api.github.com/users/jdom/following{/other_user}","gists_url":"https://api.github.com/users/jdom/gists{/gist_id}","starred_url":"https://api.github.com/users/jdom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdom/subscriptions","organizations_url":"https://api.github.com/users/jdom/orgs","repos_url":"https://api.github.com/users/jdom/repos","events_url":"https://api.github.com/users/jdom/events{/privacy}","received_events_url":"https://api.github.com/users/jdom/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/orleans/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-02-05T16:17:47Z","updated_at":"2016-02-06T02:25:47Z","closed_at":null,"body":"Based on a set of tests created by #1356, it's clear that if a grain throws a user-unhandled exception, then Orleans forwards it to the caller, but after it tampers a little bit with it.\r\nIt basically wraps it into an AggregateException and also flattens it (so it removes nested AggregateExceptions, messing with the stack trace and so on).\r\n\r\nThis entails a breaking change that would not be caught by compilers, but it seems that all who responded in #1356 agree that this should be fixed regardless.\r\n\r\nThe code to fix it is non entirely straightforward, as there are several levels of TaskContinuationSources in the middle (see #875 for example). It would be simpler to fix for now doing a one-off fix, but at some point there's a bigger follow up to avoid the unnecessary use of TaskCompletionSources (paying extra care of in what scheduler the continuations run). I will open another issue for it, nevertheless that might be easier to clean up with .NET 4.6\r\n\r\nFor now, the tests in [ExceptionPropagationTests](https://github.com/dotnet/orleans/blob/master/test/Tester/ExceptionPropagationTests.cs) are being skipped. When we implement this we'll reenable them."},"comment":{"url":"https://api.github.com/repos/dotnet/orleans/issues/comments/180660380","html_url":"https://github.com/dotnet/orleans/issues/1378#issuecomment-180660380","issue_url":"https://api.github.com/repos/dotnet/orleans/issues/1378","id":180660380,"user":{"login":"jdom","id":1361686,"avatar_url":"https://avatars.githubusercontent.com/u/1361686?v=3","gravatar_id":"","url":"https://api.github.com/users/jdom","html_url":"https://github.com/jdom","followers_url":"https://api.github.com/users/jdom/followers","following_url":"https://api.github.com/users/jdom/following{/other_user}","gists_url":"https://api.github.com/users/jdom/gists{/gist_id}","starred_url":"https://api.github.com/users/jdom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdom/subscriptions","organizations_url":"https://api.github.com/users/jdom/orgs","repos_url":"https://api.github.com/users/jdom/repos","events_url":"https://api.github.com/users/jdom/events{/privacy}","received_events_url":"https://api.github.com/users/jdom/received_events","type":"User","site_admin":false},"created_at":"2016-02-06T02:25:47Z","updated_at":"2016-02-06T02:25:47Z","body":"Hmmm, I think you might have gotten confused, or I am miss-understanding you now.\r\n> I would prefer await not to wrap it in AggregateException, but that how async await works (I think there is also a way to avoid it, with some GetAwaiter code, I think you showed that to me).\r\n\r\nA faulted `Task` always has an `AggregateException` in its `task.Exception` (that's it's type actually) that is thrown as-is when getting the `task.Result` property (or when calling `task.Wait()` in case of a non-generic Task). But calling `await task` does not ever surface this aggregate exception, no matter how many `await`s happened in between when the original exception was thrown and when you are handling it. I think you have this expectation wrong.\r\nSo if Orleans is in the middle, it should just forward the exception as is without adding its own AggregateExceptions nor modifying its stack traces... The reason this is not currently the case and why the tests are failing, is because Orleans does NOT use the `await` keyword AND instead it forwards the exceptions from one task cancellation source to the next poorly (as there is of course ways to fix these without major refactoring nor having to fall back to `await` everywhere).\r\n\r\nThe trick to use `GetAwaiter()` that you mentioned is to avoid the AggregateException when you compare it to calling `.Result` or `.Wait()`, so that it acts similar to when using the `await` keyword.\r\n\r\nIn my test code I actually called `.Wait()` in some of those cases to actually force an `AggregateException` in user code and then assert that Orleans doesn't mess with them either since they are a little bit special (and especially because I know the Orleans implementation uses `.Flatten()` at some point).\r\n\r\nIf you don't want to take my word for granted just in case, you can easily modify the tests to avoid using Orleans entirely and new up the grains  objects manually and call those same methods. You can also decorate the grain so that there is code in the middle that just calls `await` and forwards the exception to the caller, so that you test that multiple awaits in the middle do not show up as additional `AggregateException`s"}}