Invalid index in dictionary (Godot 4)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Anate

hello, me again

I am beginning to convert my project from godot 3.5 to godot 4.

I have an error that I don’t quite understand. I have that dictionary that store the info about the grid in which the world takes place. in short it is first initialized like this :

func assignCityGrid():
	for i in range(pow(gridSize * 2, 2)):
		gridData[i] ={
			"name": "plot number " + str(i+1), 
			"pos": plotCityLocation(i), 
			"status": 0, 
			"tenant_id": -1, 
			"owner": 0, 
			"usage":0, 
			"access":0, 
			"type":0, 
			"build_id": none, 
			"road_dir" : [], 
			"next_to_road" : false,
			"can_get_floor" : false,
			"floor_nb" : 0
			}

My error comes later in the script, in this function :

func cityNextToRoad() :
	pass
	for i in pow((gridSize * 2), 2) :
	----->if gridData[i]["type"] != 2 :
			var adj_cells = getAdjacentCells(i)
			for r in adj_cells :
				if r != -1 :
					if gridData[r]["type"] == 2 :
						gridData[i]["next_to_road"] = true
			var diag_cells = getDiagonalCells(i)
			for r in diag_cells :
				if r != -1 :
					if gridData[r]["type"] == 2 :
						gridData[i]["next_to_road"] = true

I pointed the error with —>, at “if gridData[i][“type”] != 2 :”

The exact error is “Invalid get index ‘0’ (on base: ‘Dictionary’).” I checked in the local variables while the game is running and the 0 index does indeed exist. What went wrong ? I use the exact same “for” loop in a lot of functions and they don’t get any error, so I don’t really understand it

thanks a lot in avance

I can only assume that you don’t have a key named 0 when you try to reference it at the error location. Just before that, what do you see if you do:

print(gridData.keys())

That’ll show you the keys in the Dictionary. I assume there’s no 0 in that result?

jgodfrey | 2023-02-07 18:23

that’s the problem, there is a 0 when I print it at this location…
the script worked perfectly in Godot 3.5.1 and other functions use the same “for” loop on the same dictionary, so I’m a bit lost with this specific error

Anate | 2023-02-07 18:48

If that’s really the case, I don’t have any explanation. I’d say you’re either missing something (likely?) or maybe you’ve discovered a bug - not sure…

jgodfrey | 2023-02-08 01:01

There is probably something i’m missing here, but I’m not sure what
thanks anyways for trying !

Anate | 2023-02-08 09:40

Happy to take a closer look if the project is available somewhere. Otherwise, I guess I don’t have much else to add.

jgodfrey | 2023-02-08 16:26

it’s not on the internet yet, it is still very early in developpement
But relative to the question, I changed the for loop to be “for i in gridData.keys()” and it works. Still strange because all the other identical “for” loop still work… I guess it’s one of Godot’s mysteries
I can send you the project in PM if you want
Thanks a lot for your reflexions though, I appreciate it

Anate | 2023-02-08 19:59

Glad you have things working. And, my offer still stands to take a look if you can get the project to me somehow.

I’d prefer to not just chalk it up to a Godot mystery. If there’s really a bug here, it’d be great to verify it, get it reported, and get it fixed… :slight_smile:

jgodfrey | 2023-02-08 20:11

I changed the for loop to be “for i in gridData.keys()”

This seems to be further evidence that 0 simply isn’t a valid key at that point in the code. But, again, without looking, I’m not sure what else to offer…

jgodfrey | 2023-02-08 20:13

it’s in the script PlotManager, line 658, function “cityNextRoad”
I commented the lines I changed and put back the old line that still creates me an error
to trigger it when the game is running you need to click the “road spawner” button in the bottom of the screen

Anate | 2023-02-08 22:17

I have the project…

jgodfrey | 2023-02-08 22:20

thanks for your fast comment !

Anate | 2023-02-08 22:21

So, I see what’s causing the problem. In your original code, here:

for i in pow((gridSize * 2), 2) :

pow returns a result of type float. So, when you iterate through that range using the above, the value of i is also of type float. However, your Dictionary keys seem to be of type int (I didn’t dig into how/why that’s the case).

So, even though the two values look the same, you’re trying to find a float(0) key in the dict, when the key is actuall an int(0).

The simplest fix seems to be to wrap that for loop in a range call, which will force the result to be int. So, this:

for i in range(pow((gridSize * 2), 2) ):

With that, the value of i will be an int, and will match your Dictionary keys.

Really, I’m not sure whether this is “as expected” or a bug, but definitely seems related to number coercion between the float and int data type.

Maybe that’s helpful - I don’t know…

jgodfrey | 2023-02-08 22:51

oooooh alright I get it. I think I changed the value to a float sometime in the recent days.
Strange that it didn’t catch an error in Godot 3, I’ll go back and check it tomorrow

Thanks a lot for taking the time to investigate !!

Anate | 2023-02-08 22:54

One other comment here… Since you’re keying your Dictionary with an int value, it might be safer, easier, (and more performant?) to just use an Array (where each element is itself a Dict). I’m not sure what you’re gaining with the Dict in this case.

jgodfrey | 2023-02-08 22:57

you’re right, I didn’t think of it that way. Thanks for the tip

Anate | 2023-02-08 23:00