{"record":{"id":"018d38648ce11389","repo":"quarkusio/quarkus","slug":"not-a-virtual-method-typeinfo","errorCode":null,"errorMessage":"Not a virtual method: [typeInfo: ]","messagePattern":"Not a virtual method: \\[typeInfo: \\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"independent-projects/qute/core/src/main/java/io/quarkus/qute/Expression.java","lineNumber":137,"sourceCode":"         * <ul>\n         * <li>type info that represents a fully qualified type name (including type parameters) -\n         * {@code |TYPE_INFO|<section-hint>};\n         * for example {@code |org.acme.Foo|},\n         * {@code |java.util.List<org.acme.Label>|} and {@code |org.acme.Foo|<when#123>}</li>\n         * <li>property; for example {@code foo} and {@code foo<loop#123>}</li>\n         * <li>virtual method; for example {@code foo.call(bar)} and {@code foo.getNames(10)<loop-element>}</li>\n         * </ul>\n         *\n         * @return the type check info\n         */\n        String getTypeInfo();\n\n        default boolean isVirtualMethod() {\n            return false;\n        }\n\n        default VirtualMethodPart asVirtualMethod() {\n            throw new IllegalStateException(\"Not a virtual method: \" + toString() + \" [typeInfo: \" + getTypeInfo() + \"]\");\n        }\n\n    }\n\n    /**\n     * Part that represents a virtual method.\n     */\n    interface VirtualMethodPart extends Part {\n\n        List<Expression> getParameters();\n\n    }\n\n}\n","sourceCodeStart":119,"sourceCodeEnd":152,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/core/src/main/java/io/quarkus/qute/Expression.java#L119-L152","documentation":"Expression.Part.asVirtualMethod() is a narrowing conversion that only ExpressionPart instances representing virtual methods support. Calling it on a part that is not a virtual method throws this IllegalStateException including the part's toString and type info.","triggerScenarios":"Casting/calling part.asVirtualMethod() during expression validation or resolution when the part is actually a property/handler part, e.g. in message bundle method validation (validateMessageBundleMethodsInTemplates) or custom ValueResolver code that assumes a method part.","commonSituations":"Template code that treats a parameterless property access {item.name} as a method call in bundle validation, or custom extension code walking expression parts assuming all are virtual methods.","solutions":["Check part.isVirtualMethod() before calling asVirtualMethod()","Fix the template so the expression is a real method invocation with parentheses and args if a virtual method is expected","In validation code, handle both property and method parts explicitly instead of assuming"],"exampleFix":"// before\nExpression.Part part = parts.get(i);\nVirtualMethodPart vm = part.asVirtualMethod(); // may throw\n// after\nif (part.isVirtualMethod()) {\n    VirtualMethodPart vm = part.asVirtualMethod();\n} else {\n    // treat as property part\n}","handlingStrategy":"type-guard","validationCode":"if (!part.isVirtualMethod()) {\n    // handle as property part instead of narrowing\n}","typeGuard":"Optional<VirtualMethodPart> asVm(Expression.Part p) {\n    return p.isVirtualMethod() ? Optional.of(p.asVirtualMethod()) : Optional.empty();\n}","tryCatchPattern":"try {\n    VirtualMethodPart vm = part.asVirtualMethod();\n} catch (IllegalStateException e) {\n    log.debug(\"Part is not a virtual method: {}\", part);\n}","preventionTips":["Always call isVirtualMethod() before asVirtualMethod()","Handle both property and method parts in expression walkers","Verify bundle method templates actually use method-call syntax with parentheses","Add tests covering property-style expressions in bundle validation"],"tags":["qute","templates","expression","illegal-state"],"backgroundTag":"not-a-virtual-method","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"}