antlr/antlr4 · error · FailedPredicateException

precpred(_ctx, )

Error message

precpred(_ctx, %d)

What it means

ParserInterpreter throws FailedPredicateException("precpred(_ctx, N)") when it walks a precedence-predicate transition and the runtime predicate test precpred(ctx, N) returns false — i.e. the parse context's precedence is too low for the alternative being entered (left-recursive rule semantics). The formatted message names the precedence level that failed. In a normal generated parser the adaptivePredict machinery avoids entering such alternatives, so this fires when the interpreter follows an ATN path the prediction would have rejected.

Solutions

  1. Ensure the serialized ATN and the runtime come from the same ANTLR version (regenerate/re-serialize)
  2. Catch FailedPredicateException and inspect e.getCtx()/e.getPredicate() to identify which precedence level failed
  3. Prefer generated parsers over ParserInterpreter when possible — prediction in generated code prunes these alternatives correctly
  4. Validate the grammar's precedence structure (checkLeftRecursion output from the tool) before interpreting it

Example fix

// before
parserInterpreter.expression(); // throws FailedPredicateException mid-parse

// after
try { parserInterpreter.expression(); }
catch (FailedPredicateException e) {
  errors.add("precedence predicate failed: " + e.getMessage()
    + " at " + e.getOffendingToken().getText());
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  parserInterpreter.startRule();
} catch (FailedPredicateException e) {
  // message is 'precpred(_ctx, N)'; ctx and offending token identify the spot
  errors.add(e.getMessage() + " at line " + e.getOffendingToken().getLine());
}

Prevention

When it happens

Trigger: Running a grammar with left-recursive expression rules through ParserInterpreter (grammar loaded at runtime, not generated code); corrupted or version-mismatched serialized ATN where precedence transitions no longer match rule contexts; manually driving visitState/transition logic.

Common situations: Generic grammar-runner tools and IDE plugins that interpret grammars; deserializing an ATN produced by a different ANTLR version than the runtime interpreting it; precedence-climbing expression grammars (expr: expr '*' expr | expr '+' expr | INT with precedence options).

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/480a4843f4ef1918. Report an issue: GitHub.

Appendix: source

Thrown at runtime/Java/src/org/antlr/v4/runtime/ParserInterpreter.java:289

				}
				break;

			case Transition.PREDICATE:
				PredicateTransition predicateTransition = (PredicateTransition)transition;
				if (!sempred(_ctx, predicateTransition.ruleIndex, predicateTransition.predIndex)) {
					throw new FailedPredicateException(this);
				}

				break;

			case Transition.ACTION:
				ActionTransition actionTransition = (ActionTransition)transition;
				action(_ctx, actionTransition.ruleIndex, actionTransition.actionIndex);
				break;

			case Transition.PRECEDENCE:
				if (!precpred(_ctx, ((PrecedencePredicateTransition)transition).precedence)) {
					throw new FailedPredicateException(this, String.format("precpred(_ctx, %d)", ((PrecedencePredicateTransition)transition).precedence));
				}
				break;

			default:
				throw new UnsupportedOperationException("Unrecognized ATN transition type.");
		}

		setState(transition.target.stateNumber);
	}

	/** Method visitDecisionState() is called when the interpreter reaches
	 *  a decision state (instance of DecisionState). It gives an opportunity
	 *  for subclasses to track interesting things.
	 */
	protected int visitDecisionState(DecisionState p) {
		int predictedAlt = 1;
		if ( p.getNumberOfTransitions()>1 ) {
			getErrorHandler().sync(this);

View on GitHub (pinned to 7d5770395b)