{"record":{"id":"91fa914505f8cb8f","repo":"Netflix/Hystrix","slug":"incompatible-return-types-ncommand-method-c-91fa91","errorCode":null,"errorMessage":"Incompatible return types. \\nCommand method: \" + commandMethod + \";\\nFallback method: \" + fallbackMethod + \";\\n\" + \"Hint: Fallback method '\" + fallbackMethod + \"' must return: \" + commandReturnType + \" or its subclass\"","messagePattern":"Incompatible return types\\. \\\\nCommand method: \" \\+ commandMethod \\+ \";\\\\nFallback method: \" \\+ fallbackMethod \\+ \";\\\\n\" \\+ \"Hint: Fallback method '\" \\+ fallbackMethod \\+ \"' must return: \" \\+ commandReturnType \\+ \" or its subclass\"","errorType":"exception","errorClass":"FallbackDefinitionException","httpStatus":null,"severity":"error","filePath":"hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/FallbackMethod.java","lineNumber":192,"sourceCode":"                        }\n                    }\n                    msg.add(String.format(error.reason + \"\\n\" + extraHint + \"Command type literal pos: %s; Fallback type literal pos: %s\",\n                            positionAsString(error.commandType, commandParametrizedTypes),\n                            positionAsString(error.fallbackType, fallbackParametrizedTypes)));\n                }\n                throw new FallbackDefinitionException(createErrorMsg(commandMethod, method, StringUtils.join(msg, \"\\n\")));\n            }\n        }\n        validatePlainReturnType(commandMethod, fallbackMethod);\n    }\n\n    private void validatePlainReturnType(Method commandMethod, Method fallbackMethod) {\n        validatePlainReturnType(commandMethod.getReturnType(), fallbackMethod.getReturnType(), commandMethod, fallbackMethod);\n    }\n\n    private void validatePlainReturnType(Class<?> commandReturnType, Class<?> fallbackReturnType, Method commandMethod, Method fallbackMethod) {\n        if (!commandReturnType.isAssignableFrom(fallbackReturnType)) {\n            throw new FallbackDefinitionException(createErrorMsg(commandMethod, fallbackMethod, \"Fallback method '\"\n                    + fallbackMethod + \"' must return: \" + commandReturnType + \" or its subclass\"));\n        }\n    }\n\n    private void validateParametrizedType(Type commandReturnType, Type fallbackReturnType, Method commandMethod, Method fallbackMethod) {\n        if (!commandReturnType.equals(fallbackReturnType)) {\n            throw new FallbackDefinitionException(createErrorMsg(commandMethod, fallbackMethod, \"Fallback method '\"\n                    + fallbackMethod + \"' must return: \" + commandReturnType + \" or its subclass\"));\n        }\n    }\n\n    private String createErrorMsg(Method commandMethod, Method fallbackMethod, String hint) {\n        return \"Incompatible return types. \\nCommand method: \" + commandMethod + \";\\nFallback method: \" + fallbackMethod + \";\\n\"\n                + (StringUtils.isNotBlank(hint) ? \"Hint: \" + hint : \"\");\n    }\n\n    private static final Result SUCCESS = Result.success();\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/Netflix/Hystrix/blob/5ce3bc58c38e7ca60ef2fe0e516e390e294ad941/hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/utils/FallbackMethod.java#L174-L210","documentation":"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).","triggerScenarios":"@HystrixCommand User getUser() with fallback String getUserFallback(); or command returns interface User while fallback returns a class implementing a different interface.","commonSituations":"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.","solutions":["Check the hint for the exact required return type","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)","If multiple commands share a fallback name, split them into type-specific fallback methods","Cover fallback definitions with a startup smoke test in CI"],"exampleFix":"// before\n@HystrixCommand\npublic User getUser(String id) { ... }\n\nprivate String getUserFallback(String id) { return \"unknown\"; }\n\n// after\n@HystrixCommand\npublic User getUser(String id) { ... }\n\nprivate User getUserFallback(String id) { return User.EMPTY; }","handlingStrategy":"validation","validationCode":"Class<?> cmdRet = commandMethod.getReturnType();\nClass<?> fbRet = fallbackMethod.getReturnType();\nif (!cmdRet.isAssignableFrom(fbRet)) {\n    throw new IllegalStateException(\"Fallback \" + fallbackMethod + \" must return \" + cmdRet + \" or subclass\");\n}","typeGuard":"boolean fallbackRawTypeOk(Class<?> commandReturnType, Class<?> fallbackReturnType) {\n    return commandReturnType.isAssignableFrom(fallbackReturnType);\n}","tryCatchPattern":"catch (FallbackDefinitionException e) { log.error(\"{}\", e.getMessage()); failBuild(e); }","preventionTips":["Change fallback return type together with command return type in the same commit","Return the command's declared type (or exact subclass) from fallbacks — never a String/Optional stand-in","CI smoke test invoking each command validates all pairs"],"tags":["hystrix","javanica","fallback","return-type","validation"],"backgroundTag":null,"analyzedSha":"5ce3bc58c38e7ca60ef2fe0e516e390e294ad941","analyzedAt":"2026-08-14T10:55:35.600Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}