{"record":{"id":"213ee5306d1c4fc5","repo":"Unity-Technologies/UnityCsReference","slug":"expression-is-not-a-valid-expression","errorCode":null,"errorMessage":"'{expression}' is not a valid expression","messagePattern":"'(.+?)' is not a valid expression","errorType":"exception","errorClass":"ExpressionNotValidException","httpStatus":null,"severity":"error","filePath":"Editor/Mono/Scripting/ScriptCompilation/VersionRanges.cs","lineNumber":54,"sourceCode":"\n        public VersionDefineExpression<TVersion> GetExpression(string expression)\n        {\n            if (string.IsNullOrEmpty(expression))\n            {\n                throw new ArgumentNullException(nameof(expression));\n            }\n\n            ExpressionParsedData parsedExpressionData = ParseExpression(expression);\n            if (m_ExpressionTypes.ContainsKey(parsedExpressionData.GenerateExpressionTypeKey))\n            {\n                ExpressionTypeValue<TVersion> expressionTypeValue = m_ExpressionTypes[parsedExpressionData.GenerateExpressionTypeKey];\n\n                return new VersionDefineExpression<TVersion>(expressionTypeValue.IsValid, parsedExpressionData.leftVersion, parsedExpressionData.rightVersion)\n                {\n                    AppliedRule = expressionTypeValue.AppliedRule,\n                };\n            }\n            throw new ExpressionNotValidException($\"'{expression}' is not a valid expression\");\n        }\n\n        private static bool Contains(string array, char doContain)\n        {\n            for (int i = 0; i < array.Length; i++)\n            {\n                if (array[i] == doContain)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static bool Contains(char[] array, char doContain)\n        {\n            for (int i = 0; i < array.Length; i++)","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/Unity-Technologies/UnityCsReference/blob/225b0fbdb57cc17d094e8056b71f8314aba56f73/Editor/Mono/Scripting/ScriptCompilation/VersionRanges.cs#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (.asmdef versionDefines expression)\n\"expression\": \"1.0,2.0\"   // or \"[1.0,)\"  or \"[,2.0]\"\n// after\n\"expression\": \"[1.0,2.0]\" // inclusive on both ends","handlingStrategy":"validation","validationCode":"// Matches the 9 meaningful shapes registered by ExpressionTypeFactory.\n// V tokens: first char must be a digit; body chars = digit/letter . - / *\nstatic readonly System.Text.RegularExpressions.Regex k_ValidRange =\n    new System.Text.RegularExpressions.Regex(\n        @\"^(?:[0-9][0-9A-Za-z.\\-/*]*\" +                                  // V        (x >= V)\n        @\"|\\[[0-9][0-9A-Za-z.\\-/*]*\\]\" +                                // [V]      (x == V)\n        @\"|\\([0-9][0-9A-Za-z.\\-/*]*,\\)\" +                              // (V,)     (x >  V)\n        @\"|\\(,[0-9][0-9A-Za-z.\\-/*]*\\]\" +                             // (,V]     (x <= V)\n        @\"|\\(,[0-9][0-9A-Za-z.\\-/*]*\\)\" +                             // (,V)     (x <  V)\n        @\"|\\[[0-9][0-9A-Za-z.\\-/*]*,[0-9][0-9A-Za-z.\\-/*]*\\]\" +       // [V1,V2]\n        @\"|\\([0-9][0-9A-Za-z.\\-/*]*,[0-9][0-9A-Za-z.\\-/*]*\\)\" +       // (V1,V2)\n        @\"|\\[[0-9][0-9A-Za-z.\\-/*]*,[0-9][0-9A-Za-z.\\-/*]*\\)\" +       // [V1,V2)\n        @\"|\\([0-9][0-9A-Za-z.\\-/*]*,[0-9][0-9A-Za-z.\\-/*]*\\])$\",      // (V1,V2]\n        System.Text.RegularExpressions.RegexOptions.Compiled);\n\nstatic bool IsValidVersionRangeExpression(string expr) =>\n    !string.IsNullOrEmpty(expr) && k_ValidRange.IsMatch(expr);","typeGuard":"static bool IsSupportedShape(string e) =>\n    !string.IsNullOrEmpty(e) && k_ValidRange.IsMatch(e);","tryCatchPattern":"// CachedVersionRangesFactory already does this at parse time;\n// if calling VersionRanges<TVersion>.GetExpression directly:\ntry { var def = ranges.GetExpression(expr); }\ncatch (ExpressionNotValidException ex) {\n    // ex.Message == \"'expr' is not a valid expression\"\n    ReportToUser(ex.Message);  // surface in the inspector / CI\n}","preventionTips":["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."],"tags":["unity","asmdef","version-range","script-compilation","validation"],"backgroundTag":null,"analyzedSha":"225b0fbdb57cc17d094e8056b71f8314aba56f73","analyzedAt":"2026-08-13T19:07:19.849Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}