dotnet/wpf · error · InvalidOperationException
SR.Format(SR.TooManyDependencyProperties, ownerType.Name +…
Error message
SR.Format(SR.TooManyDependencyProperties, ownerType.Name + "." + name)
What it means
GetUniqueGlobalIndex throws this InvalidOperationException when GlobalIndexCount reaches the limit of GlobalIndexMask (15 bits, ~32767), meaning more dependency properties have been registered than the per-process global index can represent. The message includes ownerType.name for the property that pushed the count over the limit.
Solutions
- Stop registering DPs dynamically in loops; register a fixed set of DPs and store per-item data in regular CLR properties, attached-object dictionaries, or Freezable instances
- Replace per-column DPs with a single attached property plus a value lookup keyed by column id
- Recycle/reuse already-registered DPs instead of minting new ones per entity type
Example fix
// before
foreach (var col in schema.Columns)
cols.Add(DependencyProperty.Register(col.Name, typeof(object), typeof(Row))); // unbounded
// after
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(Row));
// one DP; per-column values kept in Row's own dictionary keyed by column Defensive patterns
Strategy: validation
Validate before calling
// bounded registration check before minting DPs in bulk
if (registeredDpCount + newCount > 32000)
throw new InvalidOperationException("Approaching DependencyProperty global index limit"); Try / catch
try { var dp = DependencyProperty.Register(name, typeof(object), ownerType); }
catch (InvalidOperationException) { /* index exhausted: switch to attached property / dictionary storage */ } Prevention
- Never register DPs in unbounded loops or per data item
- Use a fixed set of DPs plus per-item storage (dictionary, attached object)
- Keep total DP registrations in the hundreds/thousands, not tens of thousands
When it happens
Trigger: Registering more than GlobalIndexMask dependency properties in one AppDomain — e.g. dynamic registration in a loop (Register/AddOwner) or an extremely large number of libraries/static DPs.
Common situations: Apps or plugin hosts that register DPs per data column or per config item in unbounded loops; massive dynamic code generation frameworks creating a DP per schema field; long-running plugin systems accumulating registrations.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- SR.Format(SR.TooManyDependencyProperties…
- SR.Format(SR.InvalidPropertyValue, _value, _property.Name)
- SR.Format(SR.ReadOnlyDesignerCoersionNotAllowed, Name)
- SR.Format(SR.ReadOnlyOverrideNotAllowed, Name)
- SR.PropertyNotReadOnly
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/8b5fc2122eb17023.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyProperty.cs:1100
{
packedData |= Flags.IsStringType;
}
_packedData = packedData;
}
// Synchronized: Covered by DependencyProperty.Synchronized
internal static int GetUniqueGlobalIndex(Type ownerType, string name)
{
// Prevent GlobalIndex from overflow. DependencyProperties are meant to be static members and are to be registered
// only via static constructors. However there is no cheap way of ensuring this, without having to do a stack walk. Hence
// concievably people could register DependencyProperties via instance methods and therefore cause the GlobalIndex to
// overflow. This check will explicitly catch this error, instead of silently malfuntioning.
if (GlobalIndexCount >= (int)Flags.GlobalIndexMask)
{
if (ownerType != null)
{
throw new InvalidOperationException(SR.Format(SR.TooManyDependencyProperties, ownerType.Name + "." + name));
}
else
{
throw new InvalidOperationException(SR.Format(SR.TooManyDependencyProperties, "ConstantProperty"));
}
}
// Covered by Synchronized by caller
return GlobalIndexCount++;
}
/// <summary>
/// This is the callback designers use to participate in the computation of property
/// values at design time. Eg. Even if the author sets Visibility to Hidden, the designer
/// wants to coerce the value to Visible at design time so that the element doesn't
/// disappear from the design surface.
/// </summary>
internal CoerceValueCallback DesignerCoerceValueCallbackView on GitHub (pinned to 81131a70a4)