stride3d/stride · error · ArgumentNullException

Value cannot be null. (Parameter 'points')

Error message

Value cannot be null. (Parameter 'points')

What it means

CanvasRenderer.DrawEllipses requires a non-null IList<Point> and throws ArgumentNullException(nameof(points)) when null. A null point list has no meaningful ellipse set to draw, so the method fails fast before allocating brushes or geometries. An empty list is explicitly allowed and returns silently.

Solutions

  1. Initialize point collections to an empty List<Point> instead of leaving them null (empty lists are handled gracefully).
  2. Null-check points at the call site and skip the draw call when null.
  3. Coalesce at the boundary: points ?? Array.Empty<Point>() or points ?? new List<Point>().
  4. If data is asynchronous, render only after the collection is materialized.

Example fix

// before
renderer.DrawEllipses(model.Points, ...); // model.Points is null
// after
var pts = model.Points ?? new List<Point>();
renderer.DrawEllipses(pts, ...);
Defensive patterns

Strategy: validation

Validate before calling

var safePoints = points ?? new List<Point>();
if (safePoints.Count == 0) return; // renderer also no-ops on empty

Type guard

static bool HasDrawablePoints(IList<Point> pts) => pts is { Count: > 0 };

Try / catch

try { renderer.DrawEllipses(points, rx, ry, fill, stroke, thickness, join, dash, offset, hitTest); }
catch (ArgumentNullException ex) when (ex.ParamName == "points") { log.Warn("DrawEllipses skipped: null points"); }

Prevention

When it happens

Trigger: Calling DrawEllipses with a null points collection — e.g. a data-bound Points property not yet populated, a LINQ query returning null by convention, or passing an uninitialized field instead of an empty collection.

Common situations: Drawing layers whose point data loads asynchronously (first render pass has null data); view models exposing nullable point collections; serialization layers that skip empty arrays so deserialized objects have null collections.

Related errors


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

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Wpf/Drawing/CanvasRenderer.cs:109

            point.Offset(-size.Width / 2, -size.Height / 2);
            var rect = new Rect(point, size);

            var ellipse = Create<Ellipse>(isHitTestVisible, rect.Left, rect.Top);

            ellipse.Fill = GetBrush(fillColor);
            SetStroke(ellipse, strokeColor, thickness, lineJoin, dashArray, dashOffset, false);

            ellipse.Height = rect.Height;
            ellipse.Width = rect.Width;
            Canvas.SetLeft(ellipse, rect.Left);
            Canvas.SetTop(ellipse, rect.Top);
        }

        /// <inheritdoc/>
        public void DrawEllipses(IList<Point> points, double radiusX, double radiusY, Color fillColor, Color strokeColor,
            double thickness, PenLineJoin lineJoin, ICollection<double> dashArray, double dashOffset, bool isHitTestVisible)
        {
            if (points == null) throw new ArgumentNullException(nameof(points));
            if (points.Count == 0)
                return;

            var fillBrush = GetBrush(fillColor);
            var strokeBrush = GetBrush(strokeColor);
            var pen = new Pen(strokeBrush, thickness)
            {
                LineJoin = lineJoin,
                DashStyle = new DashStyle(dashArray, dashOffset),
            };

            var visual = new DrawingVisual();
            var context = visual.RenderOpen();
            foreach (var point in points)
            {
                context.DrawEllipse(fillBrush, pen, point, radiusX, radiusY);
            }
            context.Close();

View on GitHub (pinned to 96fad776d2)