antlr/antlr4 · error · ArgumentException
patternTree cannot be null
Error message
patternTree cannot be null
What it means
ParseTreePatternMatcher.MatchImpl rejects a null patternTree argument. The pattern tree is the compiled form of the pattern string produced by ParseTreePatternMatcher.Compile; the recursion always supplies it, so a null means MatchImpl was invoked directly or from an override that lost the pattern tree.
Source
Thrown at runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs:399
/// which does not match
/// a corresponding node in
/// <paramref name="patternTree"/>
/// , or
/// <see langword="null"/>
/// if the match
/// was successful. The specific node returned depends on the matching
/// algorithm used by the implementation, and may be overridden.
/// </returns>
[return: Nullable]
protected internal virtual IParseTree MatchImpl(IParseTree tree, IParseTree patternTree, MultiMap<string, IParseTree> labels)
{
if (tree == null)
{
throw new ArgumentException("tree cannot be null");
}
if (patternTree == null)
{
throw new ArgumentException("patternTree cannot be null");
}
// x and <ID>, x and y, or x and x; or could be mismatched types
if (tree is ITerminalNode && patternTree is ITerminalNode)
{
ITerminalNode t1 = (ITerminalNode)tree;
ITerminalNode t2 = (ITerminalNode)patternTree;
IParseTree mismatchedNode = null;
// both are tokens and they have same type
if (t1.Symbol.Type == t2.Symbol.Type)
{
if (t2.Symbol is TokenTagToken)
{
// x and <ID>
TokenTagToken tokenTagToken = (TokenTagToken)t2.Symbol;
// track label->list-of-nodes for both token name and label (if any)
labels.Map(tokenTagToken.TokenName, tree);
if (tokenTagToken.Label != null)View on GitHub (pinned to 7d5770395b)
Solutions
- Forward the patternTree parameter that MatchImpl receives when recursing into children.
- Ensure pattern trees come from ParseTreePatternMatcher.Compile(...) / parser.CompileParseTreePattern(...) and cache misses are compiled, not skipped.
- Use the public match API instead of MatchImpl.
Example fix
// before
base.MatchImpl(tree.GetChild(i), cachedPattern /* null on miss */, labels);
// after
if (!cache.TryGetValue(key, out var ptree)) { ptree = Compile(key); cache[key] = ptree; }
base.MatchImpl(tree.GetChild(i), ptree, labels); Defensive patterns
Strategy: validation
Validate before calling
var ptree = patternTree ?? throw new InvalidOperationException("pattern tree not compiled");
var r = MatchImpl(tree, ptree, labels); Type guard
static bool HasPatternTree(IParseTree p) => p != null;
Prevention
- Forward the patternTree parameter in overrides; do not substitute possibly-null fields.
- Compile-and-cache pattern trees so lookups never yield null.
When it happens
Trigger: Calling MatchImpl(tree, null, labels) directly; an override that stores the pattern tree in a field initialized to null instead of forwarding the parameter.
Common situations: Custom matcher subclasses that restructure the recursion; caching pattern trees in a dictionary that returns null on a miss and forwarding the miss; refactors between Java and C# runtimes dropping an argument.
Related errors
- tree cannot be null
- target cannot be null.
- tokenSource cannot be null
- nextToken requires a non-null input stream.
- tokens cannot be null
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/1312c9b6932f83fa.
Report an issue: GitHub.