{"record":{"id":"6e1d6c828c4984b5","repo":"antlr/antlr4","slug":"missing-path-element-at-end-of-path","errorCode":null,"errorMessage":"Missing path element at end of path","messagePattern":"Missing path element at end of path","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/tree/xpath/XPath.java","lineNumber":159,"sourceCode":"\n\t\t\t\tcase Token.EOF :\n\t\t\t\t\tbreak loop;\n\n\t\t\t\tdefault :\n\t\t\t\t\tthrow new IllegalArgumentException(\"Unknowth path element \"+el);\n\t\t\t}\n\t\t}\n\t\treturn elements.toArray(new XPathElement[0]);\n\t}\n\n\t/**\n\t * Convert word like {@code *} or {@code ID} or {@code expr} to a path\n\t * element. {@code anywhere} is {@code true} if {@code //} precedes the\n\t * word.\n\t */\n\tprotected XPathElement getXPathElement(Token wordToken, boolean anywhere) {\n\t\tif ( wordToken.getType()==Token.EOF ) {\n\t\t\tthrow new IllegalArgumentException(\"Missing path element at end of path\");\n\t\t}\n\t\tString word = wordToken.getText();\n\t\tint ttype = parser.getTokenType(word);\n\t\tint ruleIndex = parser.getRuleIndex(word);\n\t\tswitch ( wordToken.getType() ) {\n\t\t\tcase XPathLexer.WILDCARD :\n\t\t\t\treturn anywhere ?\n\t\t\t\t\tnew XPathWildcardAnywhereElement() :\n\t\t\t\t\tnew XPathWildcardElement();\n\t\t\tcase XPathLexer.TOKEN_REF :\n\t\t\tcase XPathLexer.STRING :\n\t\t\t\tif ( ttype==Token.INVALID_TYPE ) {\n\t\t\t\t\tthrow new IllegalArgumentException(word+\n\t\t\t\t\t\t\t\t\t\t\t\t\t   \" at index \"+\n\t\t\t\t\t\t\t\t\t\t\t\t\t   wordToken.getStartIndex()+\n\t\t\t\t\t\t\t\t\t\t\t\t\t   \" isn't a valid token name\");\n\t\t\t\t}\n\t\t\t\treturn anywhere ?","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/tree/xpath/XPath.java#L141-L177","documentation":"XPath.getXPathElement expects a word token (wildcard, token ref, rule ref, or string literal) but received EOF, meaning the path ended right where an element was required. Typical trigger: a trailing '/' or '//' with nothing after it.","triggerScenarios":"new XPath(parser, \"/expr//\") or XPath.findAll(tree, \"/statement/\", parser) — any path whose last step is empty.","commonSituations":"Concatenating path fragments dynamically so a separator is appended without the following element name; trailing-slip typos in hand-written queries.","solutions":["Remove the trailing '/' or '//' or complete it with a rule name, token name, '*', or 'name:\"literal\"'","When concatenating path segments, join with '/' and trim trailing separators: path.replaceAll(\"/+$\", \"\")"],"exampleFix":"// before\nString xpath = base + \"/\"; // ends with separator\nXPath.findAll(tree, xpath, parser);\n\n// after\nString xpath = base.replaceAll(\"/+$\", \"\");\nXPath.findAll(tree, xpath, parser);","handlingStrategy":"validation","validationCode":"String cleaned = path.replaceAll(\"/+$\", \"\");\nboolean endsWithSeparator = path.endsWith(\"/\") || path.endsWith(\"//\");","typeGuard":null,"tryCatchPattern":"try { XPath.findAll(tree, path, parser); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"Missing path element\")) { /* fix trailing separator */ } }","preventionTips":["Trim trailing separators when concatenating path fragments","Keep XPath queries as named constants reviewed against the grammar"],"tags":["antlr","xpath","syntax","java"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}