quarkusio/quarkus · error · WebSocketServerException

Path parameter may not be followed by an alphanumeric chara

Error message

Path parameter  may not be followed by an alphanumeric character or underscore: 

What it means

WebSocket path templates use {param} placeholders which are rewritten to :param routing patterns. A placeholder may not be immediately followed by a letter, digit, or underscore, because the generated pattern would become ambiguous/unparseable. The build fails with WebSocketServerException naming the offending path.

Source

Thrown at extensions/websockets-next/deployment/src/main/java/io/quarkus/websockets/next/deployment/WebSocketProcessor.java:1040

            path = "/" + path;
        }
        return prefix + path;
    }

    static String getPath(String path) {
        if (path.isEmpty()) {
            return path;
        }
        StringBuilder sb = new StringBuilder();
        Matcher m = PATH_PARAM_PATTERN.matcher(path);
        while (m.find()) {
            // Replace {foo} with :foo
            String match = m.group();
            int end = m.end();
            if (end < path.length()) {
                char nextChar = path.charAt(end);
                if (Character.isAlphabetic(nextChar) || Character.isDigit(nextChar) || nextChar == '_') {
                    throw new WebSocketServerException("Path parameter " + match
                            + " may not be followed by an alphanumeric character or underscore: " + path);
                }
            }
            m.appendReplacement(sb, ":" + match.subSequence(1, match.length() - 1));
        }
        m.appendTail(sb);
        return path.startsWith("/") ? sb.toString() : "/" + sb.toString();
    }

    public static String getOriginalPath(String path) {
        StringBuilder sb = new StringBuilder();
        Matcher m = TRANSLATED_PATH_PARAM_PATTERN.matcher(path);
        while (m.find()) {
            // Replace :foo with {foo}
            String match = m.group();
            m.appendReplacement(sb, "{" + match.subSequence(1, match.length()) + "}");
        }
        m.appendTail(sb);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Insert a separator between the placeholder and any following literal: '/', '-', or '.' (e.g. {id}/x, {id}-detail).
  2. Rewrite the path so placeholders occupy whole segments.
  3. If a literal must touch the parameter, move the literal into the handler or use a different path design.

Example fix

// before
@WebSocket(path = "/users/{id}x")
// after
@WebSocket(path = "/users/{id}/x")
Defensive patterns

Strategy: validation

Validate before calling

// Validate the path before annotating: no '{...}' followed by [A-Za-z0-9_]
static boolean isValidWsPath(String path) {
    return path == null || !java.util.regex.Pattern.compile("\\{[^}]+\\}[A-Za-z0-9_]").matcher(path).find();
}

Prevention

When it happens

Trigger: Declaring @WebSocket(path = ...) where a '{param}' segment is directly followed by an alphanumeric or '_' character, e.g. path = "/users/{id}x" or "/files/{name}_backup". The regex-match loop in path conversion detects the bad following character.

Common situations: Appending a literal suffix right after a placeholder without a separator; typos when writing REST-like paths; converting existing route definitions from frameworks with different path syntax.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/7554fbf901e30296. Report an issue: GitHub.