OpenRA/OpenRA · error · InvalidDataException

Empty parenthesis at index {lastToken.Index}

Error message

Empty parenthesis at index {lastToken.Index}

What it means

Thrown by VariableExpression.Build when an opening parenthesis is immediately followed by a closing parenthesis — i.e. '()' with no expression inside. Empty parenthetical grouping has no value. The message reports the index of the opening paren.

Source

Thrown at OpenRA.Game/Support/VariableExpression.cs:628

						throw new InvalidDataException($"Unmatched closing parenthesis at index {token.Index}");

					currentOpeners.Pop();
				}

				if (token.Opens != Grouping.None)
					currentOpeners.Push(token);

				if (lastToken == null)
				{
					// Expressions can't start with a binary or unary postfix operation or closer
					if (token.LeftOperand)
						throw new InvalidDataException($"Missing value or sub-expression at beginning for `{token.Symbol}` operator");
				}
				else
				{
					// Disallow empty parentheses
					if (lastToken.Opens != Grouping.None && token.Closes != Grouping.None)
						throw new InvalidDataException($"Empty parenthesis at index {lastToken.Index}");

					// Exactly one of two consecutive tokens must take the other's sub-expression evaluation as an operand
					if (lastToken.RightOperand == token.LeftOperand)
					{
						if (lastToken.RightOperand)
							throw new InvalidDataException("Missing value or sub-expression or there is an extra operator " +
								$"`{lastToken.Symbol}` at index {lastToken.Index} or `{token.Symbol}` at index {token.Index}");
						throw new InvalidDataException($"Missing binary operation before `{token.Symbol}` at index {token.Index}");
					}
				}

				if (token.Type == TokenType.Variable)
					variables.Add(token.Symbol);

				tokens.Add(token);
				lastToken = token;
			}

View on GitHub (pinned to a520984d91)

Solutions

  1. Remove the empty '()' pair, or fill it with a valid sub-expression.
  2. Check the index in the message and inspect the expression at that position.
  3. Ensure every parenthetical group contains at least one value or operation.

Example fix

# before — empty parentheses
RequiresCondition: () && rank > 0

# after — remove or fill
RequiresCondition: rank > 0
Defensive patterns

Strategy: validation

Validate before calling

// Reject empty parentheses.
using System.Text.RegularExpressions;
if (Regex.IsMatch(expression, @"\(\s*\)"))
    throw new InvalidDataException("Empty parentheses are not valid in expressions.");

Try / catch

try
{
    var expr = new BooleanExpression(yamlValue);
}
catch (System.IO.InvalidDataException ex)
{
    // Report: fill or remove the empty parentheses.
}

Prevention

When it happens

Trigger: An expression contains '()' as a sub-expression, e.g. '() + 1' or 'rank > ()'. The parser detects lastToken.Opens and token.Closes both set on consecutive tokens.

Common situations: A modder writes '()' as a placeholder or by mistake. A template leaves empty parentheses. Copy-paste drops the inner expression.

Related errors


AI-assisted analysis of OpenRA/OpenRA@a520984d91 (2026-08-13). Data as JSON: /api/errors/e0f527d7890da7c6. Report an issue: GitHub.