JamesNK/Newtonsoft.Json · error · JsonException
Path returned multiple tokens.
Error message
Path returned multiple tokens.
What it means
Thrown by SelectToken(string path) (the single-value overload) when the JSONPath expression matches more than one token. SelectToken is documented to return exactly one JToken; because the iterator over JPath.Evaluate yields a second element, the method rejects the ambiguous query with a JsonException rather than silently returning one of the matches. Use SelectTokens (plural) when a wildcard or recursive descent legitimately matches several nodes.
Source
Thrown at Src/Newtonsoft.Json/Linq/JToken.cs:2433
/// <summary>
/// Selects a <see cref="JToken"/> using a JSONPath expression. Selects the token that matches the object path.
/// </summary>
/// <param name="path">
/// A <see cref="String"/> that contains a JSONPath expression.
/// </param>
/// <param name="settings">The <see cref="JsonSelectSettings"/> used to select tokens.</param>
/// <returns>A <see cref="JToken"/>.</returns>
public JToken? SelectToken(string path, JsonSelectSettings? settings)
{
JPath p = new JPath(path);
JToken? token = null;
foreach (JToken t in p.Evaluate(this, this, settings))
{
if (token != null)
{
throw new JsonException("Path returned multiple tokens.");
}
token = t;
}
return token;
}
/// <summary>
/// Selects a collection of elements using a JSONPath expression.
/// </summary>
/// <param name="path">
/// A <see cref="String"/> that contains a JSONPath expression.
/// </param>
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the selected elements.</returns>
public IEnumerable<JToken> SelectTokens(string path)
{
return SelectTokens(path, settings: null);View on GitHub (pinned to 4f73e74372)
Solutions
- Switch to SelectTokens(path) (plural) when multiple matches are valid, and iterate over the results.
- Tighten the JSONPath to target a single node, e.g. replace $..name with $.user.name or $.items[0].id.
- Wrap SelectToken in try/catch JsonException when the query is user-supplied and cardinality is uncertain.
Example fix
// before
var name = doc.SelectToken("$..name");
// after
var names = doc.SelectTokens("$..name").ToList();
var name = names.Count == 1 ? names[0] : null; Defensive patterns
Strategy: validation
Validate before calling
var matches = doc.SelectTokens(path).ToList();
if (matches.Count > 1) { /* use all, or tighten path */ } Type guard
static bool IsSingleMatch(JToken root, string path) => root.SelectTokens(path).Take(2).Count() == 1;
Try / catch
try { var t = doc.SelectToken(path); } catch (JsonException) { /* switch to SelectTokens */ } Prevention
- Use SelectTokens (plural) whenever the path contains .., [*], or filters.
- Tighten JSONPath expressions to single-node forms for SelectToken.
- Wrap user-supplied paths in try/catch JsonException.
When it happens
Trigger: Calling token.SelectToken("$..name") (recursive descent hitting multiple objects), token.SelectToken("$.items[*].id") (array wildcard), or any path containing '..', '[*]', or '[?(@...)]' filters on a document where more than one node satisfies the expression.
Common situations: A path that worked on a sample with a single element breaks once the array grows. Switching from a fixed property access ($.user.name) to a wildcard query without changing to SelectTokens. Reusing a path across heterogeneous documents where cardinality is not guaranteed.
Related errors
- Source value must be a JToken.
- Cannot cast {0} to {1}.
- Newtonsoft.Json support for System.ComponentModel is not com
- Argument is not a JToken.
- Could not determine new value to add to '{0}'.
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/d55a0cac0c327f0c.
Report an issue: GitHub.