{"record":{"id":"b404fdc012a90a5e","repo":"quarkusio/quarkus","slug":"no-valueexpressionresolver-is-defined","errorCode":null,"errorMessage":"No valueExpressionResolver is defined","messagePattern":"No valueExpressionResolver is defined","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MeterTagsSupport.java","lineNumber":75,"sourceCode":"\n    private static Tags getCommonTags(ArcInvocationContext context) {\n        Method method = context.getMethod();\n        String className = method.getDeclaringClass().getName();\n        String methodName = method.getName();\n        return Tags.of(\"class\", className, \"method\", methodName);\n    }\n\n    /*\n     * Precedence copied from MeterTagAnnotationHandler\n     */\n    private String resolveTagValue(MeterTag annotation, Object parameterValue) {\n        String value = null;\n        if (annotation.resolver() != NoOpValueResolver.class) {\n            ValueResolver valueResolver = valueResolvers.get(annotation.resolver());\n            value = valueResolver.resolve(parameterValue);\n        } else if (StringUtils.isNotBlank(annotation.expression())) {\n            if (valueExpressionResolver == null) {\n                throw new IllegalArgumentException(\"No valueExpressionResolver is defined\");\n            }\n            value = valueExpressionResolver.resolve(annotation.expression(), parameterValue);\n        } else if (parameterValue != null) {\n            value = parameterValue.toString();\n        }\n        return value == null ? \"\" : value;\n    }\n\n    /*\n     * Precedence copied from MeterTagAnnotationHandler\n     */\n    private static String resolveTagKey(MeterTag annotation, String parameterName) {\n        if (StringUtils.isNotBlank(annotation.value())) {\n            return annotation.value();\n        } else if (StringUtils.isNotBlank(annotation.key())) {\n            return annotation.key();\n        } else {\n            return parameterName;","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/MeterTagsSupport.java#L57-L93","documentation":"When a @MeterTag parameter uses an expression (annotation.expression() is non-blank) and no resolver class is set, Quarkus's MeterTagsSupport needs a ValueExpressionResolver bean to evaluate the expression. That resolver is injected as Instance<ValueExpressionResolver>; when no such CDI bean exists in the application it is null and resolveTagValue throws IllegalArgumentException. This mirrors Micrometer's MeterTagAnnotationHandler behavior.","triggerScenarios":"Annotating a method parameter with @MeterTag(expression = \"...\") inside a @Timed/@Counted intercepted bean, while the application defines no bean implementing io.micrometer.common.annotation.ValueExpressionResolver and the annotation's resolver() is left at NoOpValueResolver.","commonSituations":"Copying Micrometer examples that use SpEL-style expressions (Spring provides one automatically) into a Quarkus app where you must supply your own ValueExpressionResolver bean; upgrading Quarkus/Micrometer where expression support became stricter; a resolver bean that is not annotated so Arc never discovers it.","solutions":["Provide a CDI bean implementing io.micrometer.common.annotation.ValueExpressionResolver, e.g. a @Singleton class that implements resolve(String expression, Object parameterValue)","Alternatively switch the @MeterTag to use resolver = MyValueResolver.class instead of an expression, so the expression path is never taken","Remove the expression from @MeterTag and rely on the default parameterValue.toString() rendering","Verify the resolver bean is in a package scanned by Quarkus and properly annotated so Arc registers it"],"exampleFix":"// before\nvoid metric(@MeterTag(expression = \"upper\") String region) { ... }\n// throws: no ValueExpressionResolver\n\n// after\n@Singleton\npublic class UpperCaseValueExpressionResolver implements ValueExpressionResolver {\n    public String resolve(String expression, Object value) {\n        return value == null ? \"\" : value.toString().toUpperCase();\n    }\n}\n\nvoid metric(@MeterTag(expression = \"upper\") String region) { ... }","handlingStrategy":"validation","validationCode":"boolean hasExpressionResolver = CDI.current().select(ValueExpressionResolver.class).isResolvable();\nif (!hasExpressionResolver && usesMeterTagExpressions()) {\n    throw new IllegalStateException(\"Define a ValueExpressionResolver bean to use @MeterTag expressions\");\n}","typeGuard":"static boolean canResolveExpression(MeterTag tag) {\n    return tag.resolver() != NoOpValueResolver.class || tag.expression() == null || tag.expression().isBlank();\n}","tryCatchPattern":"try {\n    return invocation.proceed();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"valueExpressionResolver\")) {\n        log.error(\"@MeterTag expression used without a ValueExpressionResolver bean\");\n    }\n    throw e;\n}","preventionTips":["Always ship a @Singleton ValueExpressionResolver bean when you use @MeterTag expressions","Prefer resolver = MyResolver.class on @MeterTag over string expressions","Add a startup test that calls an @Timed method with @MeterTag params"],"tags":["quarkus","micrometer","meter-tag","cdi","missing-bean"],"backgroundTag":"missing-bean-definition","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}