Unity-Technologies/UnityCsReference · error · ExpressionNotValidException
Unknown expression: {expression}
Error message
Unknown expression: {expression} What it means
Thrown by the Invalid evaluator (VersionRangesEvaluators.cs:62), which ExpressionTypeFactory registers as the validation function for exactly one key: ExpressionTypeKey(leftSymbol:'(', rightSymbol:')', hasLeftVersion:true) with NO separator — the shape '(V)', a single version wrapped in parentheses with no comma. Unlike errors 720-724, this expression parses AND passes the dictionary lookup successfully (GetExpression returns a VersionDefineExpression whose AppliedRule is literally 'Invalid'). The throw is DEFERRED TO EVALUATION TIME, when VersionDefineExpression.IsValid is invoked against a concrete version and dispatches to the throwing lambda. It represents a shape Unity recognizes syntactically but assigns no range semantics to.
Source
Thrown at Editor/Mono/Scripting/ScriptCompilation/VersionRangesEvaluators.cs:62
return MinimumVersionExclusive(left, right, version) // left < version
&& MaximumVersionExclusive(left, right, version); // && version < right;
}
public static bool MixedInclusiveMinimumAndExclusiveMaximumVersion(TVersion left, TVersion right, TVersion version)
{
return MinimumVersionInclusive(left, right, version) // left <= version
&& MaximumVersionExclusive(left, right, version); // && version < right;
}
public static bool MixedExclusiveMinimumAndInclusiveMaximumVersion(TVersion left, TVersion right, TVersion version)
{
return MinimumVersionExclusive(left, right, version) // left < version
&& MaximumVersionInclusive(left, right, version); // && version <= right;
}
public static bool Invalid(string expression)
{
throw new ExpressionNotValidException($"Unknown expression: {expression}");
}
}
}
View on GitHub (pinned to 225b0fbdb5)
Solutions
- For 'exactly version V' use '[V]', e.g. '[1.0]'.
- For 'minimum V' (x >= V) use the bare version, e.g. '1.0'.
- For 'strictly greater than V' (x > V) use '(V,)' WITH the comma, e.g. '(1.0,)'.
- Remove the parentheses entirely if you just want '>= V'.
Example fix
// before "(1.0)" // parses OK, AppliedRule="Invalid", throws on evaluation // after "[1.0]" // x == 1.0 (or use "1.0" for x >= 1.0)
Defensive patterns
Strategy: validation
Validate before calling
// '(V)' (parens around a single version, NO comma) parses but throws on evaluation.
// Reject it up front so it never reaches the deferred Invalid evaluator.
static bool IsEvaluableShape(string e) =>
!string.IsNullOrEmpty(e) &&
!(e.StartsWith("(") && e.EndsWith(")") && !e.Contains(","));
// Full-shape guard (k_ValidRange) already excludes the '(V)' no-comma form. Type guard
static bool IsNotParenOnlySingleVersion(string e) =>
!string.IsNullOrEmpty(e) &&
!(e.StartsWith("(") && e.EndsWith(")") && !e.Contains(",")); Try / catch
// 725 throws at EVALUATION, outside CachedVersionRangesFactory's parse-time catch.
// Either pre-check AppliedRule, or wrap the evaluation call site:
var def = factory.GetExpression(expr); // succeeds for '(1.0)'
if (def.AppliedRule == "Invalid") {
ReportToUser($"'{expr}' is not an evaluable version range (use '[V]' or 'V').");
return;
}
try {
bool active = def.IsValid(def.LeftVersion, def.RightVersion, currentVersion);
}
catch (ExpressionNotValidException ex) when (ex.Message.StartsWith("Unknown expression")) {
ReportToUser(ex.Message);
} Prevention
- Never wrap a single bare version in parentheses; '(1.0)' has no meaning — use '[1.0]' for exact or '1.0' for >=.
- Always pair '(' / ')' with a comma for ranges: '(V,)', '(,V)', '(V1,V2)'.
- Check AppliedRule == 'Invalid' on any returned VersionDefineExpression before evaluating it.
- Validate the shape with k_ValidRange before saving the .asmdef; it excludes the '(V)' form.
When it happens
Trigger: Using '(1.0)' as a version-define expression. GetExpression("(1.0)") returns without error because the key is registered, but when the editor later evaluates the define against the current Unity/SemVer version the IsValid lambda runs VersionRangesEvaluators<TVersion>.Invalid("(<version>)") and throws. Because CachedVersionRangesFactory only wraps GetExpression in try/catch, this evaluation-time throw escapes the cache.
Common situations: Mistakenly wrapping a single version in parentheses expecting 'exactly this version' ('(1.0)' instead of '[1.0]'); or expecting a minimum bound and adding parens ('(1.0)' instead of '1.0' or '(1.0,)'). The error surfaces inconsistently — the field validates at parse time but explodes at build/evaluate time.
Related errors
- '{expression}' is not a valid expression
- 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
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/49979ee24b48734f.
Report an issue: GitHub.