dotnet/wpf · error · ArgumentException

SR.Format(SR.NotAmbientProperty…

Error message

SR.Format(SR.NotAmbientProperty, xamlMember.DeclaringType.Name, xamlMember.Name)

What it means

ObjectWriterContext.FindAmbientValues validates that every XamlMember passed in the properties collection has IsAmbient set. When a non-ambient property is supplied it throws ArgumentException with SR.NotAmbientProperty, naming the declaring type and member, with paramName "properties".

Solutions

  1. Add [Ambient] (System.Xaml.Schema.AmbientAttribute) to the property so IsAmbient returns true, or mark it ambient in your custom schema context.
  2. Filter the properties list before calling: only include members where xamlMember.IsAmbient is true.
  3. Ensure you are using the correct SchemaContext instance so ambient metadata is detected as intended.

Example fix

// before
var props = new[] { schemaContext.GetXamlType(typeof(Panel)).GetMember("Children"), xt.GetMember("Tag") }; // Tag is not ambient
// after
var props = new[] { schemaContext.GetXamlType(typeof(Panel)).GetMember("Children") }
    .Where(m => m.IsAmbient).ToArray();
Defensive patterns

Strategy: validation

Validate before calling

if (properties.Any(m => !m.IsAmbient))
    throw new ArgumentException("All members must be ambient", nameof(properties));

Type guard

static bool AllAmbient(IEnumerable<XamlMember> members) => members.All(m => m.IsAmbient);

Try / catch

try { FindAmbientValues(properties, ceilingTypes, stopAfterFirst); }
catch (ArgumentException ex) when (ex.ParamName == "properties")
{ /* filter out non-ambient members and retry */ }

Prevention

When it happens

Trigger: Calling the API that collects ambient values (e.g. via IAmbientProvider / XamlObjectWriter internals or custom schema context code) and passing a XamlMember in the properties array whose SchemaContext does not mark it ambient.

Common situations: Custom XAML schema contexts or ambient-property lookups where the ambient attribute ([Ambient]) is missing from the property definition; properties enumerated from the wrong type so IsAmbient is false; hand-built XamlMember lists mixing ambient and regular members.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/5b895f56118fd6d8. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Context/ObjectWriterContext.cs:317

            if (frame.Member == XamlLanguage.Initialization)
            {
                return frame.XamlType;
            }

            return frame.Member.Type;
        }

        private List<AmbientPropertyValue> FindAmbientValues(IEnumerable<XamlType> ceilingTypesEnumerable,
                                                             bool searchLiveStackOnly,
                                                             IEnumerable<XamlType> types,
                                                             XamlMember[] properties,
                                                             bool stopAfterFirst)
        {
            foreach (XamlMember xamlMember in properties)
            {
                if (!xamlMember.IsAmbient)
                {
                    throw new ArgumentException(SR.Format(SR.NotAmbientProperty, xamlMember.DeclaringType.Name, xamlMember.Name), nameof(properties));
                }
            }

            List<XamlType> ceilingTypes = ceilingTypesEnumerable is not null ? new List<XamlType>(ceilingTypesEnumerable) : null;

            List<AmbientPropertyValue> retList = new List<AmbientPropertyValue>();

            // Start the search for ambient properties and types starting with the parent frame.
            ObjectWriterFrame frame = _stack.PreviousFrame;
            ObjectWriterFrame lowerFrame = _stack.CurrentFrame;

            while (frame.Depth >= 1)
            {
                if (searchLiveStackOnly && frame.Depth <= SavedDepth)
                {
                    break;
                }

View on GitHub (pinned to 81131a70a4)