Unity-Technologies/UnityCsReference · error · ExpressionNotValidException
'{expression}' is not a valid expression
Error message
'{expression}' is not a valid expression What it means
Thrown by GetExpression (VersionRanges.cs:54) AFTER ParseExpression succeeds but the generated ExpressionTypeKey (left symbol, right symbol, presence of a comma separator, and presence of left/right version tokens) is not one of the range patterns registered in ExpressionTypeFactory.Create(). Every character already passed the lexical checks, so the defect is structural, not lexical: the combination of delimiters/separator/versions has no defined range meaning.
Source
Thrown at Editor/Mono/Scripting/ScriptCompilation/VersionRanges.cs:54
public VersionDefineExpression<TVersion> GetExpression(string expression)
{
if (string.IsNullOrEmpty(expression))
{
throw new ArgumentNullException(nameof(expression));
}
ExpressionParsedData parsedExpressionData = ParseExpression(expression);
if (m_ExpressionTypes.ContainsKey(parsedExpressionData.GenerateExpressionTypeKey))
{
ExpressionTypeValue<TVersion> expressionTypeValue = m_ExpressionTypes[parsedExpressionData.GenerateExpressionTypeKey];
return new VersionDefineExpression<TVersion>(expressionTypeValue.IsValid, parsedExpressionData.leftVersion, parsedExpressionData.rightVersion)
{
AppliedRule = expressionTypeValue.AppliedRule,
};
}
throw new ExpressionNotValidException($"'{expression}' is not a valid expression");
}
private static bool Contains(string array, char doContain)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == doContain)
{
return true;
}
}
return false;
}
private static bool Contains(char[] array, char doContain)
{
for (int i = 0; i < array.Length; i++)View on GitHub (pinned to 225b0fbdb5)
Solutions
- Rewrite the expression as one of the 9 supported shapes. For an inclusive closed range use '[V1,V2]'; for exclusive '(V1,V2)'; for mixed '[V1,V2)' or '(V1,V2]'.
- If you wrote 'V1,V2' with no brackets, change it to '[V1,V2]'.
- For open-ended bounds use the supported forms, NOT '[V,)': '>= V' is bare 'V'; '> V' is '(V,)'; '<= V' is '(,V]'; '< V' is '(,V)'.
- If one side was left empty inside brackets ('[V,]' / '[,V]'), use the proper open form above.
- Validate the expression with the regex/type-guard below before saving the .asmdef so it fails in tooling, not at build time.
Example fix
// before (.asmdef versionDefines expression) "expression": "1.0,2.0" // or "[1.0,)" or "[,2.0]" // after "expression": "[1.0,2.0]" // inclusive on both ends
Defensive patterns
Strategy: validation
Validate before calling
// Matches the 9 meaningful shapes registered by ExpressionTypeFactory.
// V tokens: first char must be a digit; body chars = digit/letter . - / *
static readonly System.Text.RegularExpressions.Regex k_ValidRange =
new System.Text.RegularExpressions.Regex(
@"^(?:[0-9][0-9A-Za-z.\-/*]*" + // V (x >= V)
@"|\[[0-9][0-9A-Za-z.\-/*]*\]" + // [V] (x == V)
@"|\([0-9][0-9A-Za-z.\-/*]*,\)" + // (V,) (x > V)
@"|\(,[0-9][0-9A-Za-z.\-/*]*\]" + // (,V] (x <= V)
@"|\(,[0-9][0-9A-Za-z.\-/*]*\)" + // (,V) (x < V)
@"|\[[0-9][0-9A-Za-z.\-/*]*,[0-9][0-9A-Za-z.\-/*]*\]" + // [V1,V2]
@"|\([0-9][0-9A-Za-z.\-/*]*,[0-9][0-9A-Za-z.\-/*]*\)" + // (V1,V2)
@"|\[[0-9][0-9A-Za-z.\-/*]*,[0-9][0-9A-Za-z.\-/*]*\)" + // [V1,V2)
@"|\([0-9][0-9A-Za-z.\-/*]*,[0-9][0-9A-Za-z.\-/*]*\])$", // (V1,V2]
System.Text.RegularExpressions.RegexOptions.Compiled);
static bool IsValidVersionRangeExpression(string expr) =>
!string.IsNullOrEmpty(expr) && k_ValidRange.IsMatch(expr); Type guard
static bool IsSupportedShape(string e) =>
!string.IsNullOrEmpty(e) && k_ValidRange.IsMatch(e); Try / catch
// CachedVersionRangesFactory already does this at parse time;
// if calling VersionRanges<TVersion>.GetExpression directly:
try { var def = ranges.GetExpression(expr); }
catch (ExpressionNotValidException ex) {
// ex.Message == "'expr' is not a valid expression"
ReportToUser(ex.Message); // surface in the inspector / CI
} Prevention
- Keep the 9-shape cheat sheet next to the inspector: V, [V], (V,), (,V], (,V), [V1,V2], (V1,V2), [V1,V2), (V1,V2].
- Run the IsValidVersionRangeExpression regex over every .asmdef in CI so malformed Version Defines fail the build early.
- Do not reuse NuGet/Maven '[V,)' open-range syntax; Unity only registers '(V,)' and '(,V)'.
- Prefer the constrained inspector input over hand-editing the versionDefines JSON array.
When it happens
Trigger: Calling VersionRanges<TVersion>.GetExpression(expr) (directly or via VersionRangesFactory / CachedVersionRangesFactory) with a string that parses cleanly but yields an unregistered key. Concrete inputs: '1.0,2.0' (comma range with NO surrounding brackets), '[1.0,)' (left bracket + right paren, only a left version), '[1.0,]' or '[,2.0]' (one side empty inside brackets), '(1.0]' (mismatched delimiters, no comma), '[]'. Each passes char validation but the resulting ExpressionTypeKey is absent from the dictionary.
Common situations: Authoring a Version Define in an .asmdef (Assembly Definition) inspector and typing a range without delimiters ('1.0,2.0') assuming it means a closed range; mixing bracket styles ('[1.0)' intending inclusive both ends); leaving one side empty ('[1.0,]'); or carrying over a NuGet/Maven habit like '[1.0,)' that Unity's grammar does not register. Also seen when hand-editing the versionDefines array of a .asmdef JSON by hand.
Related errors
- Invalid character '{leftSymbol}' in expression
- Invalid character '{rightSymbol}' in expression
- Incomplete expression, missing symbol in start or end
- '{value}' is not valid in the expression
- Unknown expression: {expression}
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/213ee5306d1c4fc5.
Report an issue: GitHub.