First, Create a subclass of CallAdapter.Factory

public class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
    private final RxJava2CallAdapterFactory original;
    private final Gson gson;

    private RxErrorHandlingCallAdapterFactory(RxJava2CallAdapterFactory original, Gson gson) {
        this.original = original;
        this.gson = gson;
    }

    public static CallAdapter.Factory create(RxJava2CallAdapterFactory original, Gson gson) {
        return new RxErrorHandlingCallAdapterFactory(original, gson);
    }

    @Override
    public CallAdapter<?, ?> get(@android.support.annotation.NonNull Type returnType,
                                 @android.support.annotation.NonNull Annotation[] annotations,
                                 @android.support.annotation.NonNull Retrofit retrofit) {
        CallAdapter<?, ?> callAdapter = original.get(returnType, annotations, retrofit);
        return new RxCallAdapterWrapper(gson, returnType, callAdapter);
    }

    private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> {
        private final Gson gson;
        private final CallAdapter<R, Object> wrapped;

        private final boolean isObservable;
        private final boolean isFlowable;
        private final boolean isSingle;
        private final boolean isMaybe;
        private final boolean isCompletable;

        @SuppressWarnings("unchecked")
        RxCallAdapterWrapper(Gson gson, Type returnType, CallAdapter wrapped) {
            this.gson = gson;
            Class<?> rawType = getRawType(returnType);
            this.isObservable = rawType == Observable.class;
            this.isFlowable = rawType == Flowable.class;
            this.isSingle = rawType == Single.class;
            this.isMaybe = rawType == Maybe.class;
            this.isCompletable = rawType == Completable.class;
            this.wrapped = (CallAdapter<R, Object>) wrapped;
        }

        @Override
        public Type responseType() {
            return wrapped.responseType();
        }

        @Override
        @SuppressWarnings("unchecked")
        public Object adapt(@android.support.annotation.NonNull Call<R> call) {
            Object object = wrapped.adapt(call);

            if (isObservable) {
                return ((Observable) object).onErrorResumeNext(new Function<Throwable, ObservableSource>() {
                    @Override
                    public ObservableSource apply(@NonNull Throwable throwable) throws Exception {
                        return Observable.error(asRetrofitException(throwable));
                    }
                });
            }

            if (isFlowable) {
                return ((Flowable) object).onErrorResumeNext(new Function<Throwable, Publisher>() {
                    @Override
                    public Publisher apply(@NonNull Throwable throwable) throws Exception {
                        return Flowable.error(asRetrofitException(throwable));
                    }
                });
            }

            if (isSingle) {
                return ((Single) object).onErrorResumeNext(new Function<Throwable, SingleSource>() {
                    @Override
                    public SingleSource apply(@NonNull Throwable throwable) throws Exception {
                        return Single.error(asRetrofitException(throwable));
                    }
                });
            }

            if (isMaybe) {
                return ((Maybe) object).onErrorResumeNext(new Function<Throwable, MaybeSource>() {
                    @Override
                    public MaybeSource apply(@NonNull Throwable throwable) throws Exception {
                        return Maybe.error(asRetrofitException(throwable));
                    }
                });
            }

            if (isCompletable) {
                return ((Completable) object).onErrorResumeNext(new Function<Throwable, CompletableSource>() {
                    @Override
                    public Completable apply(@NonNull Throwable throwable) throws Exception {
                        return new CompletableError(asRetrofitException(throwable));
                    }
                });
            }

            return null;
        }

        private Throwable asRetrofitException(Throwable throwable) {
            if (throwable instanceof HttpException) {
                HttpException httpException = (HttpException) throwable;
                Response response = httpException.response();
                return RemoteException.httpError(response.raw().request().url().toString(), response, throwable, gson);
            }

            return throwable;
        }


        private static Class<?> getRawType(Type type) {
            if (type == null) {
                throw new IllegalArgumentException("type == null");
            }

            if (type instanceof Class<?>) {
                // Type is a normal class.
                return (Class<?>) type;
            }
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;

                // I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
                // suspects some pathological case related to nested classes exists.
                Type rawType = parameterizedType.getRawType();
                if (!(rawType instanceof Class)) throw new IllegalArgumentException();
                return (Class<?>) rawType;
            }
            if (type instanceof GenericArrayType) {
                Type componentType = ((GenericArrayType) type).getGenericComponentType();
                return Array.newInstance(getRawType(componentType), 0).getClass();
            }
            if (type instanceof TypeVariable) {
                // We could use the variable's bounds, but that won't work if there are multiple. Having a raw
                // type that's more general than necessary is okay.
                return Object.class;
            }
            if (type instanceof WildcardType) {
                return getRawType(((WildcardType) type).getUpperBounds()[0]);
            }

            throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
                    + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
        }
    }
}

Then use it as

public Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
    return new Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create(RxJava2CallAdapterFactory.create(), gson))
            .build();
}

References

Retrofit 2 and Rx Java call adapter error handling