{"record":{"id":"994312952b5c3867","repo":"Netflix/Hystrix","slug":"return-type-of-cachekey-method-must-be-string-met","errorCode":null,"errorMessage":"return type of cacheKey method must be String. Method: '{}', Class: '{}'","messagePattern":"return type of cacheKey method must be String\\. Method: '(.+?)', Class: '(.+?)'","errorType":"validation","errorClass":"HystrixCachingException","httpStatus":null,"severity":"error","filePath":"hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationContextFactory.java","lineNumber":78,"sourceCode":"        if (method.isAnnotationPresent(CacheRemove.class)) {\n            CacheRemove cacheRemove = method.getAnnotation(CacheRemove.class);\n            MethodExecutionAction cacheKeyMethod = createCacheKeyAction(cacheRemove.cacheKeyMethod(), metaHolder);\n            return new CacheInvocationContext<CacheRemove>(cacheRemove, cacheKeyMethod, metaHolder.getObj(), method, metaHolder.getArgs());\n        }\n        return null;\n    }\n\n    private static MethodExecutionAction createCacheKeyAction(String method, MetaHolder metaHolder) {\n        MethodExecutionAction cacheKeyAction = null;\n        if (StringUtils.isNotBlank(method)) {\n            Method cacheKeyMethod = getDeclaredMethod(metaHolder.getObj().getClass(), method,\n                    metaHolder.getMethod().getParameterTypes());\n            if (cacheKeyMethod == null) {\n                throw new HystrixCachingException(\"method with name '\" + method + \"' doesn't exist in class '\"\n                        + metaHolder.getObj().getClass() + \"'\");\n            }\n            if (!cacheKeyMethod.getReturnType().equals(String.class)) {\n                throw new HystrixCachingException(\"return type of cacheKey method must be String. Method: '\" + method + \"', Class: '\"\n                        + metaHolder.getObj().getClass() + \"'\");\n            }\n\n            MetaHolder cMetaHolder = MetaHolder.builder().obj(metaHolder.getObj()).method(cacheKeyMethod).args(metaHolder.getArgs()).build();\n            cacheKeyAction = new MethodExecutionAction(cMetaHolder.getObj(), cacheKeyMethod, cMetaHolder.getArgs(), cMetaHolder);\n        }\n        return cacheKeyAction;\n    }\n\n}\n","sourceCodeStart":60,"sourceCodeEnd":89,"githubUrl":"https://github.com/Netflix/Hystrix/blob/5ce3bc58c38e7ca60ef2fe0e516e390e294ad941/hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/cache/CacheInvocationContextFactory.java#L60-L89","documentation":"A cacheKeyMethod must return java.lang.String, because the generated cache key is a String. Javanica checks cacheKeyMethod.getReturnType().equals(String.class) immediately after resolving the method and throws HystrixCachingException if the return type is anything else (primitives, boxed types, objects, even CharSequence subclasses do not pass — the check is exact-class equality).","triggerScenarios":"cacheKeyMethod returns int, Long, Object, or a key object type; returning CharSequence or a custom Key class instead of exactly String.","commonSituations":"Reusing an existing getId()/hashCode() helper as the cache key method; boxing mismatch where the helper returns Integer for an id that is conceptually a string.","solutions":["Change the cache key method's return type to exactly String (return String.valueOf(id) where needed).","If the helper is shared, add a thin String-returning wrapper and reference that in cacheKeyMethod.","Alternatively drop cacheKeyMethod and use @CacheKey parameter annotations to let Javanica build the key."],"exampleFix":"// before\n@CacheRemove(commandKey = \"getUser\", cacheKeyMethod = \"keyFor\")\npublic void updateUser(User u) { ... }\nprivate Long keyFor(User u) { return u.getId(); }\n\n// after\n@CacheRemove(commandKey = \"getUser\", cacheKeyMethod = \"keyFor\")\npublic void updateUser(User u) { ... }\nprivate String keyFor(User u) { return String.valueOf(u.getId()); }","handlingStrategy":"validation","validationCode":"static void assertCacheKeyMethodReturnsString(Object target, Method annotated, String keyMethodName) throws Exception {\n    if (keyMethodName == null || keyMethodName.trim().isEmpty()) return;\n    Method m = target.getClass().getMethod(keyMethodName, annotated.getParameterTypes());\n    if (!m.getReturnType().equals(String.class))\n        throw new IllegalStateException(\"cacheKeyMethod '\" + keyMethodName + \"' must return String, returns \" + m.getReturnType());\n}","typeGuard":null,"tryCatchPattern":"catch (HystrixCachingException e) with message 'return type of cacheKey method must be String' → treat as wiring bug: change the helper's return type to String and re-run; do not catch in production code.","preventionTips":["Standardize all cache key helpers to 'private String xxxKey(<same params>)'.","CI reflection test over @CacheRemove/@CacheResult annotations verifying key methods exist and return exactly String."],"tags":["hystrix","javanica","cache","cache-key","return-type"],"backgroundTag":null,"analyzedSha":"5ce3bc58c38e7ca60ef2fe0e516e390e294ad941","analyzedAt":"2026-08-14T10:55:35.600Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}