From 35dfe3d9a5f441a1bea82fdf8300b908cc17ac1b Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Wed, 19 Aug 2026 16:24:25 +1000 Subject: [PATCH] Add checks to `fromJson` when trying to convert to an array (#26109) Issue popped up when using `fromJson` into an array but the JSON passed is an object ```nim import std/[jsonutils, json] let data = parseJson """ {"key": "value"} """ var foo: seq[int] foo.fromJson(data) echo foo #> @[0] ``` Basically the `setLen` would set the size to be equal to the number of keys, but `getElems` just returns an empty array if the JSON isn't an array which lead to it just creating zero'd items in the seq without letting the user know. Felt adding the checks was better than just skipping the `setLen` since it lets the user know that there is a problem with the JSON (cherry picked from commit 81325d07452f61a578853b926eb84f3b56ef8676) --- changelog.md | 1 + lib/std/jsonutils.nim | 2 ++ tests/stdlib/tjsonutils.nim | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/changelog.md b/changelog.md index 1322e5fd7d..37f072ac32 100644 --- a/changelog.md +++ b/changelog.md @@ -90,6 +90,7 @@ parameter and result types, not just their source-level shape. Use works without single-quoting. - `std/uri`: The `?` operator now appends query parameters to an existing query string instead of replacing it. Fixes [#19782](https://github.com/nim-lang/Nim/issues/19782). +- `std/jsonutils`: `fromJson` now throws an exception when converting to `array`/`seq` if the JSON isn't an array instead of silently failing ## Language changes diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 941fb80685..e069f13550 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -238,6 +238,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = a = T() fromJson(a[], b, opt) elif T is array: + checkJson b.kind == JArray checkJson a.len == b.len, "Json array size doesn't match for " & $T var i = 0 for ai in mitems(a): @@ -248,6 +249,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = for val in b.getElems: incl a, jsonTo(val, E) elif T is seq: + checkJson b.kind == JArray a.setLen b.len for i, val in b.getElems: fromJson(a[i], val, opt) diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index 9d9188d755..e6c1a9c874 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -451,6 +451,12 @@ template fn() = let json = inner.toJson(ToJsonOptions(enumMode: joptEnumSymbol)) doAssert $json == """{"x":"hello","y":"A"}""" + block arrayTypeCheck: + let json = """{"key": "value"}""".parseJson() + var output: seq[int] + doAssertRaises(ValueError): + output.fromJson(json) + block: # bug #21638 type Something = object