Netflix/Hystrix · error · IllegalStateException

unsupported rx type: {}

Error message

unsupported rx type: {}

What it means

GenericObservableCommand.toObservable accepts only rx.Observable, rx.Completable, or rx.Single (RxJava 1.x types) as the user action's return value; anything else throws IllegalStateException. It exists because observable commands may be declared with several rx return shapes, and the bridge must convert each to Observable — an unrecognized type cannot be converted.

Source

Thrown at hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/GenericObservableCommand.java:176

            return false;
        }
        for (Class<? extends Throwable> ignoreException : ignoreExceptions) {
            if (ignoreException.isAssignableFrom(throwable.getClass())) {
                return true;
            }
        }
        return false;
    }

    private Observable toObservable(Object obj) {
        if (Observable.class.isAssignableFrom(obj.getClass())) {
            return (Observable) obj;
        } else if (Completable.class.isAssignableFrom(obj.getClass())) {
            return ((Completable) obj).toObservable();
        } else if (Single.class.isAssignableFrom(obj.getClass())) {
            return ((Single) obj).toObservable();
        } else {
            throw new IllegalStateException("unsupported rx type: " + obj.getClass());
        }
    }
}

View on GitHub (pinned to 5ce3bc58c3)

Solutions

  1. Return rx.Observable/rx.Single/rx.Completable (RxJava 1.x) from methods executed in observable mode with hystrix-javanica.
  2. Convert other async types at the boundary: e.g. wrap CompletableFuture with Observable.from(future), or Reactor mono -> Observable via mono.toFuture() bridging or adapter libraries.
  3. If the codebase has moved to RxJava2/Reactor, prefer a Hystrix adaptation layer (e.g. HystrixObservableCommand subclass written manually) or migrate off Javanica for those methods.

Example fix

// before (RxJava2 leaking into javanica)
@HystrixCommand
public io.reactivex.Single<User> getUser(String id) { ... }

// after
@HystrixCommand
public rx.Single<User> getUser(String id) { ... }
// or bridge: rx.Observable.fromFuture(completableFuture)
Defensive patterns

Strategy: validation

Validate before calling

static void assertRxJava1ReturnTypes(Class<?> clazz) {
    for (Method m : clazz.getMethods()) {
        Class<?> rt = m.getReturnType();
        if (rt.getName().startsWith("io.reactivex.") || rt.getName().startsWith("reactor.")) {
            if (m.isAnnotationPresent(HystrixCommand.class))
                throw new IllegalStateException(m + " returns " + rt + " — hystrix-javanica only supports rx.* (RxJava1) types");
        }
    }
}

Type guard

static boolean isSupportedRxType(Class<?> t) {
    return rx.Observable.class.isAssignableFrom(t)
            || rx.Completable.class.isAssignableFrom(t)
            || rx.Single.class.isAssignableFrom(t);
}

Try / catch

try { commandObservable = toObservable(actionResult); } catch (IllegalStateException e) { if (e.getMessage().startsWith("unsupported rx type")) log.error("action returned {} — convert to rx.Observable/Single/Completable (RxJava1)", resultClass); throw e; }

Prevention

When it happens

Trigger: An @HystrixCommand method executed in observable mode whose action returns an RxJava 2 type (io.reactivex.Observable/Single/Flowable/Completable), a java.util.concurrent.CompletableFuture, a plain value via a custom setup, or reactor's Flux/Mono — none of which are rx.* classes.

Common situations: Migrating a service from RxJava1 to RxJava2 while hystrix-javanica (built against RxJava1) is still in place; mixing Reactor and Hystrix in Spring WebFlux-era code; returning CompletableFuture from an observe-mode command.

Related errors


AI-assisted analysis of Netflix/Hystrix@5ce3bc58c3 (2026-08-14). Data as JSON: /api/errors/06d7da5a63212934. Report an issue: GitHub.