AxonServer is eating my query handler exceptions

I have switched to axon server (currently version 4.0.3) and now the exceptions from my query handlers are getting swallowed. In my case, I’m raising a java.util.NoSuchElementException whenever a query doesn’t find the entity it was looking for. I have a REST controller that queries via the QueryGateway abstraction and whenever the thing I’m looking for can not be found I want to return a response with a 404 status.

This used to be very simple. I just setup controller advice that reacts to the NoSuchElementException by returning the response with the desired 404 status. Now however, any time my query handlers throw any sort of exception all I get is AxonServerRemoteQueryHandlingException with some error code that doesn’t map very well concepts like NOT FOUND, or ILLEGAL ARGUMENT, so my controller has to make some big assumptions about the nature of the failure.

I would really like to be able to get at the exception I raised from the query handler. I do understand the issue related to remote class serialization, but I would gladly trade that (as it is something I can control) for the situation I’m facing now, with lots of uncertainty and assumptions.

Below is an example of one of my “controller advice” methods (ie. methods on a class that extends org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler which handler exceptions raised in a controller method)

`

@ExceptionHandler(value = {AxonServerRemoteQueryHandlingException.class})
protected ResponseEntity handleQueryException(AxonServerRemoteQueryHandlingException ex, WebRequest request) {
return handleExceptionInternal(ex,
ex.getExceptionDescriptions().stream().collect(Collectors.joining("\n * ", "\n * ", “”)), new HttpHeaders(),
ex.getErrorCode().equals(“AXONIQ-5001”) ? HttpStatus.NOT_FOUND : HttpStatus.BAD_REQUEST, request);
}

`

I’ve found the error codes defined in org.axonframework.axonserver.connector.ErrorCode however none of them really relate to my NOT FOUND scenario. I empirically deduced that “AXONIQ-5001” was always associated with my not found scenario and so I coded this way, but I really don’t like this situation. It feels like a really big problem.

Please advise!

Troy

Hi Troy,

unfortunately, you’ve hit the Achilles heel of the AxonServer Connector here. We had already identified this issue and are planning to streamline this as part of issue 885, which is scheduled for 4.1. We’re currently aiming to release 4.1 somewhere mid February.

One thing we’ll be doing is define more error codes for “standard” situations, like “not found” for commands and queries, but also allow mapping of exceptions to error messages/codes and vice versa.
Note that AXONIQ-5001 is an error code that indicates an exception that occurred inside the handler.

In your situation, though, you could argue whether “not finding” an entity is really an exception, or just a regular outcome. There’s always a lot of debate about the use of exceptions in Java. If you were to return null from your handler, you could have the rest API map that to a 404.

Cheers,

Allard

Thanks Allard!

I'll look for the enhancements to exception handling.

I don't have a problem switching my "not found" handling strategy to return null instead of raising the exception. I probably should have thought of that myself instead of fighting for my preference of raising the exception, because it just doesn't matter as long as the correct signals are reliably sent to the caller.

Thanks!

A little side-track. If there is a case of not found, you might be happier with an Optional.of(object) // Optional.empty(), instead of an object // null .

I agree with the use of Optional, I use it frequently. I have already tried to return Optional<MyModel> from my query handler, but then I can't query it through the gateway, using ResponseTypes (https://axoniq.io/apidocs/3.2/org/axonframework/queryhandling/responsetypes/ResponseTypes.html). With ResponseTypes I need my query handler to return MyModel. Unless I'm missing something.

Hi,

unfortunately, Optional is not supported as a response type, yet. This is something that would need to be expressed by the ResponseType implementation that is passed in the query. More specifically, the matches and convert methods would need to be implemented, such that Optional matches an singleInstanceOf(R.class).

There is an issue related to this (https://github.com/AxonFramework/AxonFramework/issues/552). It is something we would like to support (not through an explicit return type, but as part of the ResponseType.instanceOf(…).

Cheers,