JamesNK/Newtonsoft.Json · error · JsonException

Step cannot be zero.

Error message

Step cannot be zero.

What it means

Thrown unconditionally by ArraySliceFilter.ExecuteFilter when the slice Step property equals zero. A slice step of zero would create an infinite loop, so the filter rejects it up front at ArraySliceFilter.cs:16-18 regardless of any ErrorWhenNoMatch setting. It originates from a JSONPath slice expression of the form [start:end:step] where step is 0.

Source

Thrown at Src/Newtonsoft.Json/Linq/JsonPath/ArraySliceFilter.cs:18

using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json.Utilities;

namespace Newtonsoft.Json.Linq.JsonPath
{
    internal class ArraySliceFilter : PathFilter
    {
        public int? Start { get; set; }
        public int? End { get; set; }
        public int? Step { get; set; }

        public override IEnumerable<JToken> ExecuteFilter(JToken root, IEnumerable<JToken> current, JsonSelectSettings? settings)
        {
            if (Step == 0)
            {
                throw new JsonException("Step cannot be zero.");
            }

            foreach (JToken t in current)
            {
                if (t is JArray a)
                {
                    // set defaults for null arguments
                    int stepCount = Step ?? 1;
                    int startIndex = Start ?? ((stepCount > 0) ? 0 : a.Count - 1);
                    int stopIndex = End ?? ((stepCount > 0) ? a.Count : -1);

                    // start from the end of the list if start is negative
                    if (Start < 0)
                    {
                        startIndex = a.Count + startIndex;
                    }

                    // end from the start of the list if stop is negative

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Ensure the step portion of any slice expression is a non-zero integer (positive or negative).
  2. If the step is computed dynamically, guard it: skip the slice or use step 1 when the computed step is 0.
  3. Remove the explicit :0 from the slice and rely on the default step of 1.

Example fix

// before
token.SelectTokens($"$.data[{start}:{end}:{step}]");

// after
var safeStep = step == 0 ? 1 : step;
token.SelectTokens($"$.data[{start}:{end}:{safeStep}]");
Defensive patterns

Strategy: validation

Validate before calling

// Never let step be zero in a slice expression
int safeStep = (step == 0) ? 1 : step;
string path = $"$.data[{start}:{end}:{safeStep}";

Try / catch

try
{
    token.SelectTokens($"$.data[{start}:{end}:{step}]");
}
catch (JsonException ex) when (ex.Message.Contains("Step cannot be zero"))
{
    // retry with default step of 1
    token.SelectTokens($"$.data[{start}:{end}:1]");
}

Prevention

When it happens

Trigger: Using a JSONPath slice with an explicit zero step, e.g. token.SelectTokens("$.data[1:5:0]"), which is parsed into ArraySliceFilter { Start=1, End=5, Step=0 }. The check fires before any token is examined, so it throws even on valid arrays.

Common situations: Building a slice expression dynamically where the step value is computed and can legitimately be zero; copying a Python-style slice but passing a zero stride; off-by-one in a computed step variable.

Related errors


AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07). Data as JSON: /api/errors/b827f581c91326b9. Report an issue: GitHub.