{"record":{"id":"c3e4e8af6351f329","repo":"AvaloniaUI/Avalonia","slug":"unknown-relativesource-mode","errorCode":null,"errorMessage":"Unknown RelativeSource mode.","messagePattern":"Unknown RelativeSource mode\\.","errorType":"validation","errorClass":"ExpressionParseException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Data/Core/Parsers/BindingExpressionGrammar.cs","lineNumber":366,"sourceCode":"                        }\n                    }\n                    else\n                    {\n                        var reader = new CharacterReader(args[0].AsSpan());\n                        (ancestorNamespace, ancestorType) = ParseTypeName(ref reader);\n                        ancestorLevel = int.Parse(args[1]);\n                    }\n                }\n                nodes.Add(new AncestorNode\n                {\n                    Namespace = ancestorNamespace,\n                    TypeName = ancestorType,\n                    Level = ancestorLevel\n                });\n            }\n            else\n            {\n                throw new ExpressionParseException(r.Position, \"Unknown RelativeSource mode.\");\n            }\n\n            return State.AfterMember;\n        }\n\n        private static TypeName ParseTypeName(\n#if NET7SDK\n            scoped\n#endif\n            ref CharacterReader r)\n        {\n            ReadOnlySpan<char> ns, typeName;\n            ns = ReadOnlySpan<char>.Empty;\n            var typeNameOrNamespace = r.ParseIdentifier();\n\n            if (!r.End && r.TakeIf(':'))\n            {\n                ns = typeNameOrNamespace;","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Data/Core/Parsers/BindingExpressionGrammar.cs#L348-L384","documentation":"Thrown by ParseRelativeSource when the identifier following '$' does not match either 'self' or 'parent' — the only two supported RelativeSource modes in Avalonia's binding mini-language. The parser reads an identifier via ParseIdentifier and checks it against the two known modes; anything else falls through to the else branch.","triggerScenarios":"Writing '$templeft', '$findAncestor', '$previousData', or any '$xxx' that is not exactly '$self' or '$parent'. The identifier is compared case-sensitively via SequenceEqual against 'self' and 'parent'.","commonSituations":"Coming from WPF where RelativeSource modes include 'FindAncestor', 'PreviousData', 'TemplatedParent', 'Self' — Avalonia only supports 'self' and 'parent'; misspelling 'self' or 'parent'; using a WPF RelativeSource mode name that Avalonia does not implement.","solutions":["Use '$self' to reference the control itself or '$parent' (optionally with '[Type;level]') to reference an ancestor.","For templated parent bindings, use '$parent[Control] or the TemplatedSource in compiled bindings instead of a WPF-style mode name.","Check that the mode keyword is lowercase — the comparison is case-sensitive."],"exampleFix":"<!-- before: unsupported WPF-style mode -->\n{Binding $templeft}\n\n<!-- after: use supported mode -->\n{Binding $parent[Control]}","handlingStrategy":"validation","validationCode":"// Validate RelativeSource mode keyword\nstatic void ValidateRelativeSourceMode(string path)\n{\n    if (path.Contains('$'))\n    {\n        var match = System.Text.RegularExpressions.Regex.Match(path, @\"\\$([a-zA-Z]+)\");\n        if (match.Success)\n        {\n            var mode = match.Groups[1].Value;\n            if (mode != \"self\" && mode != \"parent\")\n                throw new ArgumentException(\n                    $\"Unknown RelativeSource mode '${mode}'. Supported: 'self', 'parent'\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var binding = new Binding(path);\n}\ncatch (ExpressionParseException ex) when (ex.Message.Contains(\"Unknown RelativeSource mode\"))\n{\n    logger.LogError($\"Unknown RelativeSource mode at column {ex.Column}: use '$self' or '$parent'\");\n}","preventionTips":["Only two modes exist: '$self' and '$parent' (case-sensitive, lowercase).","When migrating from WPF, map FindAncestor/TemplatedParent to '$parent[Type]'.","Test RelativeSource binding strings in isolation before using them in complex paths."],"tags":["avalonia","binding","xaml","binding-expression","relative-source","parser","syntax-error","wpf-migration"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}