Netflix/Hystrix · error · FallbackDefinitionException

fallback cannot return 'void' if command return type is " +

Error message

fallback cannot return 'void' if command return type is " + Completable.class.getSimpleName()

What it means

When the @HystrixCommand method returns rx.Completable, Javanica permits the fallback to return any type that can wrap completion ('everything can be wrapped into completable') EXCEPT void. validateCompletableReturnType throws FallbackDefinitionException if the fallback's return type is Void.TYPE (primitive void), since there would be no value to complete the Completable with and no way to signal a fallback result.

Source

Thrown at hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/FallbackMethod.java:156

                validateReturnType(commandMethod, method);
            }

        }
    }

    private Type getFirstParametrizedType(Method m) {
        Type gtype = m.getGenericReturnType();
        if (gtype instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) gtype;
            return pType.getActualTypeArguments()[0];
        }
        return null;
    }

    // everything can be wrapped into completable except 'void'
    private void validateCompletableReturnType(Method commandMethod, Class<?> callbackReturnType) {
        if (Void.TYPE == callbackReturnType) {
            throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, "fallback cannot return 'void' if command return type is " + Completable.class.getSimpleName()));
        }
    }

    private void validateReturnType(Method commandMethod, Method fallbackMethod) {
        if (isGenericReturnType(commandMethod)) {
            List<Type> commandParametrizedTypes = flattenTypeVariables(commandMethod.getGenericReturnType());
            List<Type> fallbackParametrizedTypes = flattenTypeVariables(fallbackMethod.getGenericReturnType());
            Result result = equalsParametrizedTypes(commandParametrizedTypes, fallbackParametrizedTypes);
            if (!result.success) {
                List<String> msg = new ArrayList<String>();
                for (Error error : result.errors) {
                    Optional<Type> parentKindOpt = getParentKind(error.commandType, commandParametrizedTypes);
                    String extraHint = "";
                    if (parentKindOpt.isPresent()) {
                        Type parentKind = parentKindOpt.get();
                        if (isParametrizedType(parentKind)) {
                            extraHint = "--> " + ((ParameterizedType) parentKind).getRawType().toString() + "<Ooops!>\n";
                        }

View on GitHub (pinned to 5ce3bc58c3)

Solutions

  1. Change the fallback return type from void to Completable (or another wrappable type such as Observable/Single)
  2. In the Completable fallback, signal completion via Completable.complete() or an error via Completable.error(e) instead of relying on void return
  3. Keep a naming/convention check in code review for Completable commands' fallbacks
  4. Add a CI test that triggers the fallback path once so the definition is validated

Example fix

// before
@HystrixCommand
public Completable doWork() { ... }

private void doWorkFallback(Throwable e) { log(e); }

// after
@HystrixCommand
public Completable doWork() { ... }

private Completable doWorkFallback(Throwable e) { log(e); return Completable.complete(); }
Defensive patterns

Strategy: validation

Validate before calling

Class<?> cmdRet = commandMethod.getReturnType();
if (Completable.class.isAssignableFrom(cmdRet) && fallbackMethod.getReturnType() == Void.TYPE) {
    throw new IllegalStateException("Completable command requires non-void fallback: " + fallbackMethod);
}

Try / catch

catch (FallbackDefinitionException e) { log.error("Completable command has void fallback: {}", e.getMessage()); failBuild(e); }

Prevention

When it happens

Trigger: @HystrixCommand Completable doWork() with a fallback declared as `void doWorkFallback(Throwable e)` (or parameterless void variant).

Common situations: Writing fallbacks for Completable-returning commands by analogy with void-returning commands; code-generation tools defaulting fallbacks to void; refactoring Observable commands to Completable while keeping void fallbacks.

Related errors


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