antlr/antlr4 · error · ArgumentException
tree cannot be null
Error message
tree cannot be null
What it means
ParseTreePatternMatcher.MatchImpl rejects a null tree argument. MatchImpl is the protected recursion engine behind ParseTreePattern.Match(); every level of the recursion passes subtree children in, and a null there indicates a structural bug (a child accessor returned null) or a custom override calling it with null. The public API never passes null from a real parse tree.
Source
Thrown at runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs:395
/// </summary>
/// <returns>
/// the first node encountered in
/// <paramref name="tree"/>
/// 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;View on GitHub (pinned to 7d5770395b)
Solutions
- Do not call MatchImpl yourself; use tree.Pattern(p).Match() / p.Match(tree).
- In overrides, guard children before recursing: skip null children or treat them as mismatches instead of passing them down.
- Fix custom IParseTree implementations so GetChild(i) never returns null for i < ChildCount.
Example fix
// before
protected override IParseTree MatchImpl(IParseTree tree, IParseTree patternTree, MultiMap<string, IParseTree> labels)
{
return base.MatchImpl(GetChildOrNull(tree, 0), patternTree, labels);
}
// after
var child = GetChildOrNull(tree, 0);
return child == null ? tree /* mismatch */ : base.MatchImpl(child, patternTree, labels); Defensive patterns
Strategy: validation
Validate before calling
// In overrides, guard children before recursing
for (int i = 0; i < tree.ChildCount; i++)
{
var child = tree.GetChild(i);
if (child == null) continue; // treat as mismatch instead of throwing
var r = MatchImpl(child, patternTree.GetChild(i), labels);
} Type guard
static bool HasTree(IParseTree t) => t != null;
Prevention
- Use the public Match API rather than calling MatchImpl directly.
- Ensure custom IParseTree implementations never return null from GetChild for valid indexes.
When it happens
Trigger: Overriding or calling MatchImpl(null, patternTree, labels) directly; a custom IParseTree implementation whose GetChild() returns null for valid indexes, which the recursion then feeds into MatchImpl.
Common situations: Subclassing the pattern matcher to customize matching; wrapping/altering parse trees with custom node types that violate the IParseTree contract; porting code from an older runtime where null children were tolerated.
Related errors
- patternTree 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/7e7fba89fba449f0.
Report an issue: GitHub.