{"record":{"id":"ae5e1ca1e0573ace","repo":"quarkusio/quarkus","slug":"prefix-path-cannot-end-with","errorCode":null,"errorMessage":"Prefix path cannot end with /","messagePattern":"Prefix path cannot end with /","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java","lineNumber":94,"sourceCode":"         * <p>\n         * The match is done on a prefix bases, so registering /foo will also match /bar. Exact\n         * path matches are taken into account first.\n         * <p>\n         * If / is specified as the path then it will replace the default handler.\n         *\n         * @param path The path\n         * @param handler The handler\n         */\n        void addPrefixPath(final String path, final T handler) {\n            if (path.isEmpty()) {\n                throw new IllegalArgumentException(\"Path not specified\");\n            }\n\n            if (STRING_PATH_SEPARATOR.equals(path)) {\n                this.defaultHandler = handler;\n                return;\n            } else if (path.endsWith(STRING_PATH_SEPARATOR)) {\n                throw new RuntimeException(\"Prefix path cannot end with /\");\n            }\n\n            pathsBuilder.put(path, handler);\n        }\n\n        private int[] buildLengths(SubstringMap<T> paths) {\n            final Set<Integer> lengths = new TreeSet<>(new Comparator<>() {\n                @Override\n                public int compare(Integer o1, Integer o2) {\n                    return -o1.compareTo(o2);\n                }\n            });\n            for (String p : paths.keys()) {\n                lengths.add(p.length());\n            }\n\n            int[] lengthArray = new int[lengths.size()];\n            int pos = 0;","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/mapping/PathMatcher.java#L76-L112","documentation":"PathMatcher.addPrefixPath rejects prefix paths that end with a trailing slash. Prefix paths are matched by string-prefix comparison, so a trailing slash is invalid; the framework normalizes this itself and a path like \"/foo/\" would never match correctly.","triggerScenarios":"Calling PathMatcher.addPrefixPath(\"/foo/\", handler) — any registered prefix path whose last character is '/' (other than the exact root \"/\", which is handled as the default handler).","commonSituations":"Constructing route paths by concatenation (\"/api/\" + name) leaving trailing slashes; user-supplied configuration of route prefixes with trailing slash; converting full-path routes to prefix routes without stripping the trailing slash.","solutions":["Strip the trailing slash before registration: if (path.endsWith(\"/\") && path.length() > 1) path = path.substring(0, path.length() - 1)","Fix the route configuration or @Path annotation so it does not end with '/'","Use the exact root \"/\" only if you intend to register the default handler"],"exampleFix":"// before\nmatcher.addPrefixPath(\"/api/\", handler); // throws\n\n// after\nString prefix = \"/api/\".replaceAll(\"/$\", \"\");\nmatcher.addPrefixPath(prefix, handler); // \"/api\"","handlingStrategy":"validation","validationCode":"if (path != null && path.length() > 1 && path.endsWith(\"/\")) {\n    throw new IllegalArgumentException(\"Prefix path cannot end with /: \" + path);\n}","typeGuard":null,"tryCatchPattern":"try {\n    matcher.addPrefixPath(path, handler);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"cannot end with /\")) {\n        matcher.addPrefixPath(stripTrailingSlash(path), handler);\n    } else throw e;\n}","preventionTips":["Strip trailing slashes when building paths via concatenation","Centralize path construction in one utility that normalizes slashes","Validate user- or config-supplied route prefixes before registration"],"tags":["routing","path-matching","trailing-slash"],"backgroundTag":"invalid-route-path-trailing-slash","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"}