stride3d/stride · error · InvalidOperationException

Direction is in neutral position

Error message

Direction is in neutral position

What it means

Direction.GetTicks converts the current direction into ticks on a circular scale. If the underlying value is null — the direction is in its neutral/rest position with no deflection — it throws InvalidOperationException because there is no rotation to convert.

Solutions

  1. Check whether the direction has a value before calling GetTicks (e.g. inspect HasValue/neutral state)
  2. Skip tick computation when the input is neutral and treat it as 0 in caller logic
  3. Use the gamepad's axis/index values instead when neutral readings matter

Example fix

// before
int ticks = direction.GetTicks(maxValue);
// after
int ticks = direction.HasValue ? direction.GetTicks(maxValue) : 0;
Defensive patterns

Strategy: validation

Validate before calling

if (!direction.HasValue) return 0;
int ticks = direction.GetTicks(maxValue);

Type guard

bool IsActive(Direction d) => d.HasValue;

Try / catch

try { ticks = direction.GetTicks(maxValue); }
catch (InvalidOperationException) { ticks = 0; }

Prevention

When it happens

Trigger: Calling GetTicks on a Direction instance whose backing value has not been set (e.g. a gamepad stick or trigger at rest, or a Direction created but never updated) before reading tick values.

Common situations: Polling a gamepad's virtual 'Direction' property on the first frame before any input event; reading rotation ticks for a device returning neutral position (stick centered).

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/a1e04265e76e0c54. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Input/Direction.cs:64

        /// with 0/1 corresponding to the direction (0,1), 1/4 corresponding to (1,0), etc.
        /// </summary>
        /// <param name="value">The amount of ticks clockwise from the Up direction (numerator)</param>
        /// <param name="maxValue">The number of ticks representing a full rotation (denominator)</param>
        /// <returns>A direction with ratio <paramref name="value"/> over <paramref name="maxValue"/></returns>
        public static Direction FromTicks(int value, int maxValue)
        {
            return new Direction((int)(MaxValue / maxValue * value));
        }

        /// <summary>
        /// Retrieves the amount of ticks clockwise from the Up direction
        /// </summary>
        /// <param name="maxValue">The number of ticks representing a full rotation</param>
        /// <returns></returns>
        public int GetTicks(int maxValue)
        {
            if (!value.HasValue)
                throw new InvalidOperationException("Direction is in neutral position");
            if (maxValue <= 0)
                throw new ArgumentOutOfRangeException(nameof(maxValue));
            
            return (int)Math.Round(value.Value / ((double)MaxValue / (uint)maxValue)) % maxValue;
        }

        public static explicit operator Vector2(Direction value)
        {
            if (!value.value.HasValue)
                return Vector2.Zero;

            return new Vector2
            {
                X = (float)Math.Sin(value.value.Value * FullAngleInverse),
                Y = (float)Math.Cos(value.value.Value * FullAngleInverse),
            };
        }

View on GitHub (pinned to 96fad776d2)