@Nonnull
    @Override
    public HttpResponse onServiceException(ServiceRequestContext ctx, Throwable cause) {
        // TODO(minwoox): Add more specific conditions such as returning 400 for IllegalArgumentException
        //                when we reach v2.0. Currently, an IllegalArgumentException is handled only for
        //                annotated services.
        final boolean isAnnotatedService = ctx.config().service().as(AnnotatedService.class) != null;
        if (isAnnotatedService) {
            if (cause instanceof IllegalArgumentException) {
                return internalRenderStatus(ctx, ctx.request().headers(),
                                            HttpStatus.BAD_REQUEST, cause);
            }
        }

        if (cause instanceof HttpStatusException ||
            cause instanceof HttpResponseException) {
            // Use HttpStatusException or HttpResponseException itself because it already contains a status
            // or response.
            return HttpResponse.ofFailure(cause);
        }

        if (cause instanceof ContentTooLargeException) {
            return internalRenderStatus(ctx, ctx.request().headers(),
                                        HttpStatus.REQUEST_ENTITY_TOO_LARGE, cause);
        }

        if (cause instanceof RequestCancellationException) {
            // A stream has been cancelled. No need to send a response with a status.
            return HttpResponse.ofFailure(cause);
        }

        if (cause instanceof RequestTimeoutException) {
            final HttpStatus status;
            final RequestContextExtension ctxExtension = ctx.as(RequestContextExtension.class);
            assert ctxExtension != null;
            final DecodedHttpRequest request = (DecodedHttpRequest) ctxExtension.originalRequest();
            if (request.isClosedSuccessfully()) {
                status = HttpStatus.SERVICE_UNAVAILABLE;
            } else {
                // The server didn't receive the request fully yet.
                status = HttpStatus.REQUEST_TIMEOUT;
            }
            return internalRenderStatus(ctx, ctx.request().headers(), status, cause);
        }

        if (cause instanceof ShuttingDownException) {
            return internalRenderStatus(ctx, ctx.request().headers(),
                                        HttpStatus.SERVICE_UNAVAILABLE, cause);
        }

        return internalRenderStatus(ctx, ctx.request().headers(),
                                    HttpStatus.INTERNAL_SERVER_ERROR, cause);
    }
Converts the specified {@link Throwable} to an {@link HttpResponse}.
core/src/main/java/com/linecorp/armeria/server/DefaultServerErrorHandler.java