{"record":{"id":"92cca697a76d1d24","repo":"dotnet/maui","slug":"path-contains-an-empty-part","errorCode":null,"errorMessage":"Path contains an empty part","messagePattern":"Path contains an empty part","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"src/Controls/src/Core/BindingExpression.cs","lineNumber":235,"sourceCode":"\t\t\tstring p = Path.Trim();\n\n\t\t\tvar last = new BindingExpressionPart(this, \".\");\n\t\t\t_parts.Add(last);\n\n\t\t\tif (p[0] == '.')\n\t\t\t{\n\t\t\t\tif (p.Length == 1)\n\t\t\t\t\treturn;\n\n\t\t\t\tp = p.Substring(1);\n\t\t\t}\n\n\t\t\tstring[] pathParts = p.Split(ExpressionSplit);\n\t\t\tfor (var i = 0; i < pathParts.Length; i++)\n\t\t\t{\n\t\t\t\tstring part = pathParts[i].Trim();\n\t\t\t\tif (part == string.Empty)\n\t\t\t\t\tthrow new FormatException(\"Path contains an empty part\");\n\n\t\t\t\tBindingExpressionPart indexer = null;\n\n\t\t\t\tint lbIndex = part.IndexOf(\"[\", StringComparison.Ordinal);\n\t\t\t\tif (lbIndex != -1)\n\t\t\t\t{\n\t\t\t\t\tint rbIndex = part.Length - 1;\n\t\t\t\t\tif (part[rbIndex] != ']')\n\t\t\t\t\t\tthrow new FormatException(\"Indexer did not contain closing bracket\");\n\n\t\t\t\t\tint argLength = rbIndex - lbIndex - 1;\n\t\t\t\t\tif (argLength == 0)\n\t\t\t\t\t\tthrow new FormatException(\"Indexer did not contain arguments\");\n\n\t\t\t\t\tstring argString = part.Substring(lbIndex + 1, argLength);\n\t\t\t\t\tindexer = new BindingExpressionPart(this, argString, true);\n\n\t\t\t\t\tpart = part.Substring(0, lbIndex);","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/dotnet/maui/blob/f377ff1c5ee04d334d8a925f50c83a6b7afddf03/src/Controls/src/Core/BindingExpression.cs#L217-L253","documentation":"Thrown while parsing the binding path string when, after splitting on '.' and trimming, a path part is the empty string. This indicates a malformed path such as leading/trailing/consecutive dots (e.g. \"A..B\", \".A\", \"A.\").","triggerScenarios":"Constructing new Binding(\"A..B\"), new Binding(\".Name\"), new Binding(\"Name.\"), or any path where Split('.') yields an empty token. Dynamically building path strings with string concatenation that leaves stray dots.","commonSituations":"Building paths from nullable/optional segments (string.Format(\"{0}.{1}\") where a segment is empty). Reading paths from config/JSON with trailing dots. User input feeding a binding path.","solutions":["Sanitize the path: remove empty segments and leading/trailing dots before constructing the Binding.","Build paths with a helper that joins non-empty parts with '.'.","Validate path tokens against a property whitelist and reject malformed input early."],"exampleFix":"// before\nvar path = $\"{parent}.{child}\"; // child is \"\" -> \"Parent.\"\nvar b = new Binding(path);\n\n// after\nvar parts = new[] { parent, child }.Where(s => !string.IsNullOrWhiteSpace(s));\nvar path = string.Join(\".\", parts);\nvar b = new Binding(path);","handlingStrategy":"validation","validationCode":"static string SanitizePath(string raw)\n{\n    var parts = raw.Split('.').Where(p => !string.IsNullOrWhiteSpace(p));\n    return string.Join(\".\", parts);\n}\nvar binding = new Binding(SanitizePath(rawPath));","typeGuard":"static bool IsValidBindingPath(string p) =>\n    !string.IsNullOrWhiteSpace(p) &&\n    p.Split('.').All(seg => !string.IsNullOrWhiteSpace(seg));","tryCatchPattern":null,"preventionTips":["Build paths by joining non-empty segments with '.'.","Reject user/config paths with consecutive or leading/trailing dots.","Unit-test dynamic path construction."],"tags":["maui","binding","path","validation","format"],"backgroundTag":null,"analyzedSha":"f377ff1c5ee04d334d8a925f50c83a6b7afddf03","analyzedAt":"2026-08-13T14:26:18.069Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}