dotnet/maui · error · ArgumentException

Not a valid type of BindingMode. Property: {returnType} {dec

Error message

Not a valid type of BindingMode. Property: {returnType} {declaringType.Name}.{propertyName}. Default binding mode: {defaultBindingMode}

What it means

ArgumentException thrown by the BindableProperty constructor when defaultBindingMode is not one of the defined BindingMode values (Default, OneWay, OneWayToSource, TwoWay, OneTime). The code deliberately avoids Enum.IsDefined for performance and instead whitelists the five valid modes; anything else (including a raw cast of an undefined int) is rejected, naming the offending property and mode.

Source

Thrown at src/Controls/src/Core/BindableProperty.cs:203

		private static int _nextInternalId = int.MinValue;
		internal readonly int InternalId;

		BindableProperty(string propertyName, [DynamicallyAccessedMembers(ReturnTypeMembers)] Type returnType, [DynamicallyAccessedMembers(DeclaringTypeMembers)] Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
								 ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
								 CoerceValueDelegate coerceValue = null, BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false, CreateDefaultValueDelegate defaultValueCreator = null)
		{
			if (propertyName == null)
				throw new ArgumentNullException(nameof(propertyName));
			if (returnType is null)
				throw new ArgumentNullException(nameof(returnType));
			if (declaringType is null)
				throw new ArgumentNullException(nameof(declaringType));
			
			InternalId = Interlocked.Increment(ref _nextInternalId);

			// don't use Enum.IsDefined as its redonkulously expensive for what it does
			if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
				throw new ArgumentException($"Not a valid type of BindingMode. Property: {returnType} {declaringType.Name}.{propertyName}. Default binding mode: {defaultBindingMode}", nameof(defaultBindingMode));

			if (defaultValue == null && Nullable.GetUnderlyingType(returnType) == null && returnType.IsValueType)
				defaultValue = Activator.CreateInstance(returnType);

			if (defaultValue != null && !returnType.IsInstanceOfType(defaultValue))
				throw new ArgumentException($"Default value did not match return type. Property: {returnType} {declaringType.Name}.{propertyName} Default value type: {defaultValue.GetType().Name}, ", nameof(defaultValue));

			if (defaultBindingMode == BindingMode.Default)
				defaultBindingMode = BindingMode.OneWay;

			PropertyName = propertyName;
			ReturnType = returnType;
			DeclaringType = declaringType;
			DefaultValue = defaultValue;
			DefaultBindingMode = defaultBindingMode;
			PropertyChanged = propertyChanged;
			PropertyChanging = propertyChanging;
			ValidateValue = validateValue;

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Use a named BindingMode value (BindingMode.TwoWay, OneWay, OneWayToSource, OneTime, or Default).
  2. If the mode comes from data, validate it against the five known values before passing it in.
  3. Recompile any binary that was built against an older MAUI enum surface.

Example fix

// before
var mode = (BindingMode)userInput; // userInput could be out of range
var bp = BindableProperty.Create(nameof(X), typeof(int), typeof(V), 0, mode);

// after
var valid = mode is BindingMode.Default or BindingMode.OneWay or BindingMode.OneWayToSource
            or BindingMode.TwoWay or BindingMode.OneTime;
if (!valid) throw new ArgumentOutOfRangeException(nameof(userInput));
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidMode(BindingMode m) =>
    m is BindingMode.Default or BindingMode.OneWay or BindingMode.OneWayToSource
      or BindingMode.TwoWay or BindingMode.OneTime;

if (!IsValidMode(mode)) throw new ArgumentOutOfRangeException(nameof(mode));

Type guard

static bool IsValidMode(BindingMode m) =>
    m is BindingMode.Default or BindingMode.OneWay or BindingMode.OneWayToSource
      or BindingMode.TwoWay or BindingMode.OneTime;

Prevention

When it happens

Trigger: Calling BindableProperty.Create(..., mode: (BindingMode)99); casting an arbitrary integer to BindingMode; a stale enum value removed in a newer MAUI version being referenced by a compiled binary.

Common situations: Binary deserialization or reflection that assigns an out-of-range int to a BindingMode field; referencing an old assembly compiled against a previous enum definition; hand-rolled code-generation emitting numeric mode literals.

Related errors


AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13). Data as JSON: /api/errors/1ad5a7940c0758ed. Report an issue: GitHub.