{"record":{"id":"ea18c7485f83e646","repo":"dotnet/wpf","slug":"sr-parserattributeargslow","errorCode":null,"errorMessage":"SR.ParserAttributeArgsLow","messagePattern":"SR\\.ParserAttributeArgsLow","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/Shared/System/Windows/Markup/ReflectionHelper.cs","lineNumber":347,"sourceCode":"                // \"test\" is the Constructor Argument\n                IList<CustomAttributeTypedArgument> constructorArguments = cad.ConstructorArguments;\n                if (constructorArguments.Count == 1 && !noArgs)\n                {\n                    CustomAttributeTypedArgument tca = constructorArguments[0];\n                    attrValue = tca.Value as string;\n#if PBTCOMPILER\n                    if (attrValue == null && allowTypeAlso && tca.ArgumentType == GetMscorlibType(typeof(Type)))\n#else\n                    if (attrValue is null && allowTypeAlso && tca.ArgumentType == typeof(Type))\n#endif\n                    {\n                        typeValue = tca.Value as Type;\n                        attrValue = typeValue.AssemblyQualifiedName;\n                    }\n\n                    if (attrValue is null)\n                    {\n                        throw new ArgumentException(SR.Format(SR.ParserAttributeArgsLow, attrType.Name));\n                    }\n                }\n                else if (constructorArguments.Count == 0)\n                {\n                    // zeroArgsAllowed = true for CPA for example.\n                    // CPA with no args is valid and would mean that this type is overriding a base CPA\n                    if (noArgs || zeroArgsAllowed)\n                    {\n                        attrValue = string.Empty;\n                    }\n                    else\n                    {\n                        throw new ArgumentException(SR.Format(SR.ParserAttributeArgsLow, attrType.Name));\n                    }\n                }\n                else\n                {\n                    throw new ArgumentException(SR.Format(SR.ParserAttributeArgsHigh, attrType.Name));","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/Shared/System/Windows/Markup/ReflectionHelper.cs#L329-L365","documentation":"ReflectionHelper.GetCustomAttributeData extracts a single string (or, when allowTypeAlso, typeof(Type)) constructor argument from a CustomAttributeData for the expected attribute type. If the single argument is neither a string nor a Type (attrValue remains null), or an attribute that requires an argument has zero arguments, it throws ArgumentException(SR.ParserAttributeArgsLow, attrType.Name) — i.e. the attribute was used with fewer/simpler constructor arguments than this reflection helper supports.","triggerScenarios":"An attribute consumed by the XAML parser (e.g. ContentPropertyAttribute, XamlSetMarkupExtensionAttribute-style lookups, friend-assembly checks) is applied with an argument type other than string/Type — e.g. [Attr(42)] or [Attr(EnumValue.X)] — or with no constructor argument when one is required.","commonSituations":"Custom markup/CPA attributes authored with non-string constructor parameters (int, enum, bool) that WPF's reflection-only parser cannot interpret; attribute assemblies built with different constructor overloads; reflection-only load paths where typed arguments aren't resolved.","solutions":["Change the attribute usage to pass a single string or typeof(Type) constructor argument, e.g. [ContentProperty(\"Text\")] instead of a non-string value.","Add a string-based constructor to the custom attribute and keep the typed overload only for direct (non-parser) use.","If the attribute legitimately needs zero args, ensure the caller passes zeroArgsAllowed/noArgs appropriately (as CPA does).","Update the referenced attribute assembly so the constructor signature matches what the WPF XAML parser expects."],"exampleFix":"// before\npublic class MyContentAttribute : Attribute { public MyContentAttribute(int index) {...} }\n[MyContent(3)] // ParserAttributeArgsLow at parse time\n// after\npublic class MyContentAttribute : Attribute { public MyContentAttribute(string name) {...} }\n[MyContent(\"Content\")]","handlingStrategy":"validation","validationCode":"// Audit custom attributes consumed by the XAML parser: single string or typeof(Type) ctor arg only\nbool parserCompatible(ConstructorInfo ctor) =>\n    ctor.GetParameters().Length == 1 &&\n    (ctor.GetParameters()[0].ParameterType == typeof(string) || ctor.GetParameters()[0].ParameterType == typeof(Type));","typeGuard":"static bool IsValidParserAttributeArg(object arg) => arg is string || arg is Type;","tryCatchPattern":"try { data = ReflectionHelper.GetCustomAttributeData(type, attrType, out typeValue, allowTypeAlso); }\ncatch (ArgumentException ex) { log.Error($\"Attribute {attrType.Name} used with unsupported constructor arguments: {ex.Message}\"); }","preventionTips":["Design parser-consumed attributes with string or Type constructor parameters","Test custom attributes through reflection-only XAML parsing early","Avoid enum/int/bool constructor arguments on attributes read by the WPF parser"],"tags":["xaml","reflection","attributes","argument-exception","wpf"],"backgroundTag":"invalid-argument","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}