{"record":{"id":"d55a0cac0c327f0c","repo":"JamesNK/Newtonsoft.Json","slug":"path-returned-multiple-tokens","errorCode":null,"errorMessage":"Path returned multiple tokens.","messagePattern":"Path returned multiple tokens\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"Src/Newtonsoft.Json/Linq/JToken.cs","lineNumber":2433,"sourceCode":"\n        /// <summary>\n        /// Selects a <see cref=\"JToken\"/> using a JSONPath expression. Selects the token that matches the object path.\n        /// </summary>\n        /// <param name=\"path\">\n        /// A <see cref=\"String\"/> that contains a JSONPath expression.\n        /// </param>\n        /// <param name=\"settings\">The <see cref=\"JsonSelectSettings\"/> used to select tokens.</param>\n        /// <returns>A <see cref=\"JToken\"/>.</returns>\n        public JToken? SelectToken(string path, JsonSelectSettings? settings)\n        {\n            JPath p = new JPath(path);\n\n            JToken? token = null;\n            foreach (JToken t in p.Evaluate(this, this, settings))\n            {\n                if (token != null)\n                {\n                    throw new JsonException(\"Path returned multiple tokens.\");\n                }\n\n                token = t;\n            }\n\n            return token;\n        }\n\n        /// <summary>\n        /// Selects a collection of elements using a JSONPath expression.\n        /// </summary>\n        /// <param name=\"path\">\n        /// A <see cref=\"String\"/> that contains a JSONPath expression.\n        /// </param>\n        /// <returns>An <see cref=\"IEnumerable{T}\"/> of <see cref=\"JToken\"/> that contains the selected elements.</returns>\n        public IEnumerable<JToken> SelectTokens(string path)\n        {\n            return SelectTokens(path, settings: null);","sourceCodeStart":2415,"sourceCodeEnd":2451,"githubUrl":"https://github.com/JamesNK/Newtonsoft.Json/blob/4f73e74372445108d2c1bda37b36e6f5e43402e0/Src/Newtonsoft.Json/Linq/JToken.cs#L2415-L2451","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvar name = doc.SelectToken(\"$..name\");\n\n// after\nvar names = doc.SelectTokens(\"$..name\").ToList();\nvar name = names.Count == 1 ? names[0] : null;","handlingStrategy":"validation","validationCode":"var matches = doc.SelectTokens(path).ToList();\nif (matches.Count > 1) { /* use all, or tighten path */ }","typeGuard":"static bool IsSingleMatch(JToken root, string path) => root.SelectTokens(path).Take(2).Count() == 1;","tryCatchPattern":"try { var t = doc.SelectToken(path); } catch (JsonException) { /* switch to SelectTokens */ }","preventionTips":["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."],"tags":["jsonpath","selecttoken","linq-to-json","cardinality","jsonexception"],"analyzedSha":"4f73e74372445108d2c1bda37b36e6f5e43402e0","analyzedAt":"2026-08-07T06:10:08.596Z","schemaVersion":2},"datasetVersion":"2026-08-07T07:17:06.508Z"}