Hello. I was trying to assign a string to index “short” on dictionary “key_inv” but received the error:
Invalid set index ‘short’ (on base: ‘Dictionary’) with value of type ‘String’
I am certain the index was set with a string. I included a screenshot of my code and the dictionary at the moment. The dictionary does show that the index “short” had a string previously assigned, so I’m not sure why it’s sending this error.
This error has occurred to me before and is quite inconsistent. I once had the same error in another scene where it occurred if I run the scene itself, but it was completely fine when I entered the scene from another. This is very confusing, so thanks for helping!
I just have something else to add. I seemingly fixed the issue by just running print(InvData.key_inv[pos]) right before the line with the error, so it seems that the error has something to do with the dictionary not being properly loaded yet? This seems to track with previous occurrences of this error, but now I just want to know why this is necessary.
That does sound like a race condition with data being loaded. How/where are you populating this dictionary?
It’s interesting that the error is in attempting to set a value in the dictionary rather than attempting to read a value. What happens if you instead do something like:
# [...]
else:
InvData.key_inv[pos] = {
"short": "Book x" + str(State.forest["..."]),
"text": "Overdue books. Should be returned to the..."
}
That is, stomp the array entry with an entirely new dictionary?
Initially, I stored the dictionary as a constant which looks like this:
{
“name”: “Library Book”,
“type”: “key”,
“text”: “An overdue book. Should be returned to the library.”,
“short”: “Book”,
}
The dictionary gets set to a position in the array “key_inv” whenever the player obtains the item. However, if the game is loaded from a save file, the some position in the array would get set with data (the same dictionary) saved on a JSON file. I’m going to assume it has something to do with that. That’s kinda the journey that this dictionary takes.
Thanks for the suggestion. There was no error. I went with a less elegant solution of just making a random local variable set to the dictionary stored in the array.
This was your problem. When you declare something constant using the const keyword you are telling the precompiler that the variable will not change - it is immutable.
Your bug happened when you lied to the compiler and tried to add something to an immutable variable.
The reason it worked after the print statement is most likely what happened is that the print statement made a mutable local variable copy of the Dictionary, and so what you changed was a temporary version of the Dictionary that would only last while it was in scope. If you tried to use it in another function, the key/value pair you added would be gone again. (If my theory is correct.) This is potentially a bug, though I don’t know for sure.
Either way, the lesson here (for any language) is if you declare a constant you can never change it later. Ever.
Thanks for the tips. However, the line that’s producing the error did not try to change the constant dictionary but a previously saved copy. Maybe setting the dictionary as a constant did have some effects, so I’ll change it and see what happens.
I can’t see your code, so I can’t explain causality, but Dictionaries in Godot are treated like objects and passed by Reference not Value. What this means is that if you assign the Dictionary to another variable, you aren’t passing the contents of the Dictionary, but a reference to the memory address where it lives. This makes passing Dictionaries around very fast. But it also means that when you think you are copying a Dictionary, you are not.
If you want to make a new copy of a Dictionary you must use duplicate() and even then if you do not set deep = true you will only be getting references to nested Array, Dictionary and Resource values.
On a completely different note, if you want to modify a value, don’t make it const. Even if you can get the value copied somehow, you now have used up twice the memory for the same thing as if you’d just made it a regular variable to begin with.
I see then. This also explains how I don’t run into this issue a lot, since most of the time the dictionaries are copied off a save file. I’m assuming, in that case, it’s not passing a reference but a value. Thank you very much for your help.