Only "String" or "StringName" can be used as index for type "JSON", but received "int"

Godot Version

v4.4.1.stable.official [49a5bc7b6]

Question

I’m a little confused about this error message that I received. I’ve only ever used C# before so if this is somehow expected behaviour in GDScript then I’d love to know why.

The following code, according to Godot, is incorrect:

var json: JSON = response.body_as_json()
var monster: Monster = JsonToMonster(json[0])

However, this code, is apparently perfectly fine:

var json: JSON = response.body_as_json()
for jsonEntry in json:
	var monster: Monster = JsonToMonster(jsonEntry)

My function called JsonToMonster’s signature looks like this:

func JsonToMonster(json: JSON) -> Monster:

Why is the second option “correct” but the first one isn’t? And how can I make the first one work, because I need to pick a specific element in some cases.
I understand the error message itself, it’s expecting a string to identify part of the Json, but why can’t it accept an int?

My guess is that because of how Json sort of work like dictionaries where they store data with keys (in the form of strings) referring to them.

Like:

{
    "key1" : {
        "item1",
        "item2"
    }
}

I’m not sure how it works in GdScript but in c# when using dictionary you’d have to do something like “dictionary[“key1”]” as opposed to “dictionary[0]”.

Might be why you can’t use indexes in this context. Tho I could be wrong since I do not use GDScript and I am not particularly familiar with it.

Not always, the example you showed me can happen, but in my case, the json file looks like this:

[
  {
    "id": 1,
    "monsterName": "RedactedCuzNDA",
    "otherStuffEtc...": 100,
   },
   {
      "id": 2,
      "monsterName": "RedactedCuzNDA",
      "otherStuffEtc...": 200,
   },
]

Then you might have to convert it to an array of Json objects? Then maybe you could use indexers.

If i remember correctly, converting this Json object to a Variant in Godot would result in an Array of Dictionaries which you could then use indexers and instantiate your monsters from said Dictionaries.

There might be a better way to do it, like I said, not the most knowledgeable when it comes to GDScript.

1 Like

Turns out this is correct. It seems I can get back a simple Array, so doing this more or less achieves what I originally wanted:

var json: Array = response.body_as_json()
var monster: Monster = JsonToMonster(json[0])

Although it’s really odd that this is no longer considered a JSON object, for example, in this case, json[0] is now a Dictionary, not JSON.

So the function name body_as_json doesn’t exactly do what one would expect from the name.

But also, interestingly enough, if I do what I did originally:

var json: JSON = response.body_as_json()
for jsonEntry in json:
	var monster: Monster = JsonToMonster(jsonEntry)

This is still a json, and the object I get in my JsonToMonster function is, indeed, a JSON object. So I’m not sure what’s going on here?

I assume this is because Godot has implicit casting for Json to Arrays.

Sort of like how you can do:

var test: StringName = "string_name"
var test2: string = test

Or:

var num: int = 1
var num2: float = num

The above example works totally even tho the values assigned does have the same types, the engine just knows how to cast one to another.

1 Like

Ahh yes, I’m starting to remember why I dropped JS as well and went with C# for almost everything in my life hah.

But anyway, I more or less get why it happens, even if I don’t really agree with it, thank you for the help!

1 Like

A JSON object can be a collection of key/value pairs or a list of values. From JSON

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

Because of this, in Godot, a JSON object can be represented by Dictionary or an Array then, because it can be both, the different ways to parse a JSON string returns a Variant

You can know at runtime if its a Dictionary or an Array with @GlobalScope.typeof() or by using the is keyword like:

if value is Dictionary:
    pass
elif value is Array:
    pass
2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.