{"record":{"id":"49979ee24b48734f","repo":"Unity-Technologies/UnityCsReference","slug":"unknown-expression-expression","errorCode":null,"errorMessage":"Unknown expression: {expression}","messagePattern":"Unknown expression: (.+?)","errorType":"exception","errorClass":"ExpressionNotValidException","httpStatus":null,"severity":"error","filePath":"Editor/Mono/Scripting/ScriptCompilation/VersionRangesEvaluators.cs","lineNumber":62,"sourceCode":"            return MinimumVersionExclusive(left, right, version)  // left < version\n                && MaximumVersionExclusive(left, right, version); // && version < right;\n        }\n\n        public static bool MixedInclusiveMinimumAndExclusiveMaximumVersion(TVersion left, TVersion right, TVersion version)\n        {\n            return MinimumVersionInclusive(left, right, version)  // left <= version\n                && MaximumVersionExclusive(left, right, version); // && version < right;\n        }\n\n        public static bool MixedExclusiveMinimumAndInclusiveMaximumVersion(TVersion left, TVersion right, TVersion version)\n        {\n            return MinimumVersionExclusive(left, right, version)  // left < version\n                && MaximumVersionInclusive(left, right, version); // && version <= right;\n        }\n\n        public static bool Invalid(string expression)\n        {\n            throw new ExpressionNotValidException($\"Unknown expression: {expression}\");\n        }\n    }\n}\n","sourceCodeStart":44,"sourceCodeEnd":66,"githubUrl":"https://github.com/Unity-Technologies/UnityCsReference/blob/225b0fbdb57cc17d094e8056b71f8314aba56f73/Editor/Mono/Scripting/ScriptCompilation/VersionRangesEvaluators.cs#L44-L66","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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'."],"exampleFix":"// before\n\"(1.0)\"     // parses OK, AppliedRule=\"Invalid\", throws on evaluation\n// after\n\"[1.0]\"     // x == 1.0   (or use \"1.0\" for x >= 1.0)","handlingStrategy":"validation","validationCode":"// '(V)' (parens around a single version, NO comma) parses but throws on evaluation.\n// Reject it up front so it never reaches the deferred Invalid evaluator.\nstatic bool IsEvaluableShape(string e) =>\n    !string.IsNullOrEmpty(e) &&\n    !(e.StartsWith(\"(\") && e.EndsWith(\")\") && !e.Contains(\",\"));\n\n// Full-shape guard (k_ValidRange) already excludes the '(V)' no-comma form.","typeGuard":"static bool IsNotParenOnlySingleVersion(string e) =>\n    !string.IsNullOrEmpty(e) &&\n    !(e.StartsWith(\"(\") && e.EndsWith(\")\") && !e.Contains(\",\"));","tryCatchPattern":"// 725 throws at EVALUATION, outside CachedVersionRangesFactory's parse-time catch.\n// Either pre-check AppliedRule, or wrap the evaluation call site:\nvar def = factory.GetExpression(expr);          // succeeds for '(1.0)'\nif (def.AppliedRule == \"Invalid\") {\n    ReportToUser($\"'{expr}' is not an evaluable version range (use '[V]' or 'V').\");\n    return;\n}\ntry {\n    bool active = def.IsValid(def.LeftVersion, def.RightVersion, currentVersion);\n}\ncatch (ExpressionNotValidException ex) when (ex.Message.StartsWith(\"Unknown expression\")) {\n    ReportToUser(ex.Message);\n}","preventionTips":["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."],"tags":["unity","asmdef","version-range","script-compilation","evaluation"],"backgroundTag":null,"analyzedSha":"225b0fbdb57cc17d094e8056b71f8314aba56f73","analyzedAt":"2026-08-13T19:07:19.849Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}