jhy/jsoup · error · Selector.SelectorParseException

Unknown combinator

Error message

Unknown combinator '%s'

What it means

Grammar error in QueryParser.combinator: the parser read a combinator character between two simple selectors that is not one of '>', ' ', '+', or '~'. This means the selector contained an unsupported binary operator at a combinator position — an invalid user-supplied CSS query, not an internal fault.

Solutions

  1. Correct the selector to use only the supported combinators: descendant (whitespace), '>' (child), '+' (adjacent sibling), '~' (general sibling).
  2. Catch Selector.SelectorParseException and validate combinator characters before passing user input to Selector.parse.
  3. Check for typos or stray characters (e.g. '<', '>>') in the query between compound selectors.
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at src/main/java/org/jsoup/select/QueryParser.java:166 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of jhy/jsoup@9851ac5d9c (2026-09-08). Data as JSON: /api/errors/31f94eb36e139ade. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/org/jsoup/select/QueryParser.java:166

            throw new Selector.SelectorParseException("Could not parse query '%s': unexpected token at '%s'", query, tq.remainder());
        return left;
    }

    static Evaluator combinator(Evaluator left, char combinator, Evaluator right) {
        switch (combinator) {
            case '>':
                ImmediateParentRun run = left instanceof ImmediateParentRun ?
                    (ImmediateParentRun) left : new ImmediateParentRun(left);
                run.add(right);
                return run;
            case ' ':
                return and(new StructuralEvaluator.Ancestor(left), right);
            case '+':
                return and(new StructuralEvaluator.ImmediatePreviousSibling(left), right);
            case '~':
                return and(new StructuralEvaluator.PreviousSibling(left), right);
            default:
                throw new Selector.SelectorParseException("Unknown combinator '%s'", combinator);
        }
    }

    @Nullable Evaluator parseSubclass() {
        //  Subclass: ID | Class | Attribute | Pseudo
        if      (tq.matchChomp('#'))    return byId();
        else if (tq.matchChomp('.'))    return byClass();
        else if (tq.matches('['))       return byAttribute();
        else if (tq.matchChomp("::"))   return parseNodeSelector(); // ::comment etc
        else if (tq.matchChomp(':'))    return parsePseudoSelector();
        else                            return null;
    }

    /** Merge two evals into an Or. */
    static Evaluator or(Evaluator left, Evaluator right) {
        if (left instanceof CombiningEvaluator.Or) {
            ((CombiningEvaluator.Or) left).add(right);
            return left;

View on GitHub (pinned to 9851ac5d9c)