{"record":{"id":"9cc12af50d10a817","repo":"quarkusio/quarkus","slug":"unexpected-tag-tag","errorCode":null,"errorMessage":"Unexpected tag: \" + tag","messagePattern":"Unexpected tag: \" \\+ tag","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java","lineNumber":463,"sourceCode":"    private void flushTag() {\n        state = State.TEXT;\n        String content = buffer.toString().trim();\n        String tagStr = START_DELIMITER + content + END_DELIMITER;\n\n        Tag tag = Tag.from(content.charAt(0), config.expressionCommand());\n        switch (tag) {\n            // a section/block start; {#if}, {#else}, etc.\n            case SECTION -> sectionStart(content, tagStr);\n            // a section/block end\n            case SECTION_END -> sectionEnd(content, tagStr);\n            // parameter declaration; {@org.acme.Foo foo}\n            case PARAM -> parameterDeclaration(content, tagStr);\n            case EXPRESSION -> sectionStack.peek()\n                    .currentBlock()\n                    .addNode(new ExpressionNode(\n                            createExpression(config.expressionCommand() != null ? content.substring(1) : content),\n                            engine));\n            default -> throw new IllegalArgumentException(\"Unexpected tag: \" + tag);\n        }\n        this.buffer = new StringBuilder();\n    }\n\n    private void sectionStart(String content, String tag) {\n        boolean isEmptySection = false;\n        if (content.charAt(content.length() - 1) == Tag.SECTION_END.command) {\n            content = content.substring(0, content.length() - 1);\n            isEmptySection = true;\n        }\n\n        Iterator<String> iter = splitSectionParams(content, this);\n        if (!iter.hasNext()) {\n            throw error(ParserError.NO_SECTION_NAME, \"no section name declared for {tag}\").argument(\"tag\", tag).build();\n        }\n        String sectionName = iter.next();\n        sectionName = sectionName.substring(1, sectionName.length());\n","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java#L445-L481","documentation":"Thrown by Qute's Parser.flushTag when a template tag's type does not match any known tag kind (PARAM, EXPRESSION, section, comment, CDATA, etc.). It indicates an internal parser inconsistency rather than invalid template syntax, since the lexer normally assigns a valid Tag enum to every token.","triggerScenarios":"A Tag value reaches Parser.flushTag() that is not handled in the switch — typically caused by adding a custom Parser.Tag via EngineBuilder.addParserHook/custom parser hooks, or by a parser/lexer bug where a delimiter character produced an unmapped tag type.","commonSituations":"Developers writing custom Qute parser hooks that emit custom tags the core flushTag switch doesn't handle; upgrading Qute versions where tag handling changed and copied parser-hook code is out of sync; syntax-highlighting/preprocessing tools injecting malformed tag tokens.","solutions":["Inspect your ParserHook / custom tag implementations and ensure they only emit known Parser.Tag values or register handling for new ones.","Check the template content near the reported position for unusual characters custom code may have transformed into an unknown tag.","Update the Quarkus/Qute extension version consistently with any custom parsing code to align tag enums.","If reproducible with vanilla templates, file a Qute issue with the template snippet — it indicates a lexer/parser bug."],"exampleFix":"// before (custom parser hook emitting an unmapped tag)\nbuilder.addParserHook(parser -> parser.addTag(\"$custom\", myTag));\n\n// after (use only supported Tag values, e.g. SECTION for custom sections)\nbuilder.addParserHook(parser -> parser.addTag(\"$custom\", Parser.Tag.SECTION));","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    engine.parse(templateContent);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Unexpected tag:\")) {\n        // audit custom ParserHooks / report parser bug with template snippet\n    } else {\n        throw e;\n    }\n}","preventionTips":["Only emit supported Parser.Tag values from custom parser hooks","Keep custom parser code in sync with the Qute version in use","Test templates that exercise custom delimiters in CI"],"tags":["qute","template-parsing","illegal-argument"],"backgroundTag":"unhandled-parser-tag","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}