dotnet/wpf · error · InvalidOperationException

SR.Format(SR.PathParametersIndexOutOfRange, index…

Error message

SR.Format(SR.PathParametersIndexOutOfRange, index, PathParameters.Count)

What it means

ResolvePropertyName throws this InvalidOperationException when the path string references a parameter index that does not exist in PathParameters. Property names written as '(n)' index into the PathParameters collection; if index < 0 or index >= PathParameters.Count and throwOnError is true, resolution cannot proceed and the path is invalid.

Solutions

  1. Add one accessor to PathParameters for every '(n)' reference in the path string, in order
  2. Fix the numeric index inside the path string so it is within [0, PathParameters.Count)
  3. Replace the '(n)' indexed syntax with literal property names if accessors are not needed
  4. Validate the path string and PathParameters.Count before constructing/using the PropertyPath

Example fix

// before
var path = new PropertyPath("(2).Value"); // only 2 accessors added
path.PathParameters.Add(typeof(A).GetProperty("X"));
path.PathParameters.Add(typeof(B).GetProperty("Y"));
// after
var path = new PropertyPath("(1).Value");
path.PathParameters.Add(typeof(A).GetProperty("X"));
path.PathParameters.Add(typeof(B).GetProperty("Y"));
Defensive patterns

Strategy: validation

Validate before calling

// pathString is the raw path; count '(n)' references and compare
int maxIdx = System.Text.RegularExpressions.Regex.Matches(pathString, "\\((\\d+)\\)")
    .Select(m => int.Parse(m.Groups[1].Value)).DefaultIfEmpty(-1).Max();
bool inRange = maxIdx < path.PathParameters.Count;

Type guard

bool IndexInRange(int i, System.Collections.ICollection c) => i >= 0 && i < c.Count;

Try / catch

try { path.ResolvePropertyName(index, item, context, throwOnError: true); }
catch (InvalidOperationException ex) when (ex.Message.Contains("out of range")) { /* fix index or add parameter */ }

Prevention

When it happens

Trigger: A path string like '(5).Text' when PathParameters.Count is 3; calling new PropertyPath(pathString) with '(n)' references but never adding the corresponding accessors; negative indices from malformed path syntax.

Common situations: Copy-pasting property path strings between bindings without updating the PathParameters collection; generating paths dynamically where the accessor count depends on runtime data; typos in the numeric index inside parentheses.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/PropertyPath.cs:560

            string propertyName = name;
            int index;

            // first see if the name is an index into the parameter list
            if (IsParameterIndex(name, out index))
            {
                if (0 <= index && index < PathParameters.Count)
                {
                    object accessor = PathParameters[index];
                    // always throw if the accessor isn't valid - this error cannot
                    // be corrected later on.
                    if (!IsValidAccessor(accessor))
                        throw new InvalidOperationException(SR.Format(SR.PropertyPathInvalidAccessor,
                                    (accessor != null) ? accessor.GetType().FullName : "null"));

                    return accessor;
                }
                else if (throwOnError)
                    throw new InvalidOperationException(SR.Format(SR.PathParametersIndexOutOfRange, index, PathParameters.Count));
                else return null;
            }

            // handle attached-property syntax:  (TypeName.PropertyName)
            if (IsPropertyReference(name))
            {
                name = name.Substring(1, name.Length-2);

                int lastIndex = name.LastIndexOf('.');
                if (lastIndex >= 0)
                {
                    // attached property - get the owner type
                    propertyName = name.Substring(lastIndex + 1).Trim();
                    string ownerName = name.Substring(0, lastIndex).Trim();
                    ownerType = GetTypeFromName(ownerName, context);
                    if (ownerType == null && throwOnError)
                        throw new InvalidOperationException(SR.Format(SR.PropertyPathNoOwnerType, ownerName));
                }

View on GitHub (pinned to 81131a70a4)