Netflix/Hystrix · error · FallbackDefinitionException

Incompatible return types. \nCommand method: " +…

Error message

Incompatible return types. \nCommand method: " + commandMethod + ";\nFallback method: " + fallbackMethod + ";\n" + "Hint: Fallback method '" + fallbackMethod + "' must return: " + commandReturnType + " or its subclass"

What it means

validatePlainReturnType checks the RAW (non-generic) return types of command and fallback via Class.isAssignableFrom. If the fallback's raw return type is not the command's return type or a subclass, FallbackDefinitionException is thrown with the 'Incompatible return types ... must return: <type> or its subclass' hint (message template includes both method signatures).

Solutions

  1. Check the hint for the exact required return type
  2. Change the fallback's return type to the command's type or a subclass of it (assignability direction: fallback type must fit INTO command type)
  3. If multiple commands share a fallback name, split them into type-specific fallback methods
  4. Cover fallback definitions with a startup smoke test in CI

Example fix

// before
@HystrixCommand
public User getUser(String id) { ... }

private String getUserFallback(String id) { return "unknown"; }

// after
@HystrixCommand
public User getUser(String id) { ... }

private User getUserFallback(String id) { return User.EMPTY; }
Defensive patterns

Strategy: validation

Validate before calling

Class<?> cmdRet = commandMethod.getReturnType();
Class<?> fbRet = fallbackMethod.getReturnType();
if (!cmdRet.isAssignableFrom(fbRet)) {
    throw new IllegalStateException("Fallback " + fallbackMethod + " must return " + cmdRet + " or subclass");
}

Type guard

boolean fallbackRawTypeOk(Class<?> commandReturnType, Class<?> fallbackReturnType) {
    return commandReturnType.isAssignableFrom(fallbackReturnType);
}

Try / catch

catch (FallbackDefinitionException e) { log.error("{}", e.getMessage()); failBuild(e); }

Prevention

When it happens

Trigger: @HystrixCommand User getUser() with fallback String getUserFallback(); or command returns interface User while fallback returns a class implementing a different interface.

Common situations: Fallback written to return a defensive default of the wrong type (e.g. Optional.empty vs null-bearing DTO); refactoring the command's return type without updating fallbacks; overloads sharing a fallback name with different return types.

Related errors


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

Appendix: source

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

                        }
                    }
                    msg.add(String.format(error.reason + "\n" + extraHint + "Command type literal pos: %s; Fallback type literal pos: %s",
                            positionAsString(error.commandType, commandParametrizedTypes),
                            positionAsString(error.fallbackType, fallbackParametrizedTypes)));
                }
                throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, StringUtils.join(msg, "\n")));
            }
        }
        validatePlainReturnType(commandMethod, fallbackMethod);
    }

    private void validatePlainReturnType(Method commandMethod, Method fallbackMethod) {
        validatePlainReturnType(commandMethod.getReturnType(), fallbackMethod.getReturnType(), commandMethod, fallbackMethod);
    }

    private void validatePlainReturnType(Class<?> commandReturnType, Class<?> fallbackReturnType, Method commandMethod, Method fallbackMethod) {
        if (!commandReturnType.isAssignableFrom(fallbackReturnType)) {
            throw new FallbackDefinitionException(createErrorMsg(commandMethod, fallbackMethod, "Fallback method '"
                    + fallbackMethod + "' must return: " + commandReturnType + " or its subclass"));
        }
    }

    private void validateParametrizedType(Type commandReturnType, Type fallbackReturnType, Method commandMethod, Method fallbackMethod) {
        if (!commandReturnType.equals(fallbackReturnType)) {
            throw new FallbackDefinitionException(createErrorMsg(commandMethod, fallbackMethod, "Fallback method '"
                    + fallbackMethod + "' must return: " + commandReturnType + " or its subclass"));
        }
    }

    private String createErrorMsg(Method commandMethod, Method fallbackMethod, String hint) {
        return "Incompatible return types. \nCommand method: " + commandMethod + ";\nFallback method: " + fallbackMethod + ";\n"
                + (StringUtils.isNotBlank(hint) ? "Hint: " + hint : "");
    }

    private static final Result SUCCESS = Result.success();

View on GitHub (pinned to 5ce3bc58c3)