stride3d/stride · error · ArgumentException

Can't handle included both of positive and negative in type.

Error message

Can't handle { nameof(heightRange) } included both of positive and negative in { heightType } type.

What it means

Byte heightfields can only encode heights on one side of zero, because byte values are mapped into a range that cannot straddle both positive and negative with this conversion. CheckHeightParameters throws when a Byte-type heightmap's range has X negative and Y positive (signs summing to 0).

Solutions

  1. Shift the height range so it lies entirely on one side of zero (e.g. 0..max) for Byte type.
  2. Switch HeightType to Short or Float, which support ranges crossing zero.
  3. Offset the height data so the minimum becomes 0 and store the offset elsewhere.
  4. Validate with IsValid() and normalize the range before creating colliders.

Example fix

// before
heightmap.HeightType = HeightfieldTypes.Byte;
heightmap.HeightRange = new FloatRange(-10f, 10f);
// after
heightmap.HeightType = HeightfieldTypes.Byte;
heightmap.HeightRange = new FloatRange(0f, 20f); // shift data by +10
Defensive patterns

Strategy: validation

Validate before calling

if (heightType == HeightfieldTypes.Byte && Math.Sign(range.X) + Math.Sign(range.Y) == 0) range = new FloatRange(0f, range.Y - range.X);

Type guard

bool ByteSafeRange(HeightfieldTypes t, FloatRange r) => t != HeightfieldTypes.Byte || (Math.Sign(r.X) + Math.Sign(r.Y)) != 0;

Try / catch

try { CheckHeightParameters(size, type, range, scale, true); } catch (ArgumentException) { /* shift range or switch to Short/Float */ }

Prevention

When it happens

Trigger: HeightType = HeightfieldTypes.Byte with a HeightRange like (-1, 1) or (-10, 100); using ConvertToByteHeights with a range crossing zero.

Common situations: Terrain with sea level at 0 where artists keep symmetric positive/negative ranges; switching HeightType from Short/Float to Byte without adjusting the range.

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 stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/c87818270000dfe5. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Physics/Engine/HeightmapUtils.cs:49

                    throw new ArgumentException($"{ nameof(heightScale) } should be 1 in { heightType } type.");
                }

                // HeightRange

                if (heightRange.Y < heightRange.X)
                {
                    throw new ArgumentException($"{ nameof(heightRange) }.{ nameof(heightRange.Y) } should be greater than { nameof(heightRange.X) }.");
                }

                if (Math.Abs((heightRange.Y / heightScale) - (heightRange.X / heightScale)) < 1)
                {
                    throw new ArgumentException($"{ nameof(heightRange) } is too short.");
                }

                if ((heightType == HeightfieldTypes.Byte) &&
                    (Math.Sign(heightRange.X) + Math.Sign(heightRange.Y)) == 0)
                {
                    throw new ArgumentException($"Can't handle { nameof(heightRange) } included both of positive and negative in { heightType } type.");
                }
            }
            catch (ArgumentException)
            {
                if (throwExceptionWhenInvalid) throw;

                return false;
            }

            return true;
        }

        public static float ConvertToFloatHeight(float minValue, float maxValue, float value) => MathUtil.InverseLerp(minValue, maxValue, MathUtil.Clamp(value, minValue, maxValue)) * 2 - 1;
        public static short ConvertToShortHeight(float minValue, float maxValue, float value) => (short)Math.Round(ConvertToFloatHeight(minValue, maxValue, value) * short.MaxValue, MidpointRounding.AwayFromZero);
        public static byte ConvertToByteHeight(float minValue, float maxValue, float value) => (byte)Math.Round(MathUtil.InverseLerp(minValue, maxValue, MathUtil.Clamp(value, minValue, maxValue)) * byte.MaxValue, MidpointRounding.AwayFromZero);

        public static float[] ConvertToFloatHeights(float[] values, float minValue, float maxValue) => values.Select((v) => ConvertToFloatHeight(minValue, maxValue, v)).ToArray();
        public static float[] ConvertToFloatHeights(short[] values, short minValue = short.MinValue, short maxValue = short.MaxValue) => values.Select((v) => ConvertToFloatHeight(minValue, maxValue, v)).ToArray();

View on GitHub (pinned to 96fad776d2)