godotengine / godotengine/godot
Unable to correctly save resource with typed dictionary after changing concrete value type to Variant
- Dominant language
- C++
- Stars
- 117k
- Forks
- 26.8k
- PR merge metrics
- PR metrics pending
Description
### Tested versions
Reproduceable in v4.4.1.stable.official [49a5bc7b6], v4.7.2.stable.official [ed1daf0bf].
### System information
Godot v4.4.1.stable - Windows 10 (build 19045) - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3050 Ti Laptop GPU (NVIDIA; 32.0.15.6119) - AMD Ryzen 5 5600H with Radeon Graphics (12 threads)
### Issue description
After creating a custom `Resource` with typed dictionary of concrete types (e.x. String, float) changing the value type from `float` to `Variant` will result in the engine not updating dictionary type in the serialized resource file.
When running a scene with the corrupted resource file, the engine gives very ambiguous error message in the debugger window:
```
E 0:00:01:319 assign: Unable to convert value at key "string_not_float" from "String" to "float".
Method/function failed.
core/variant/dictionary.cpp:509 @ assign()
```
The resource file before the change:
```gdscript
extends Resource
class_name ResourceWithTypedDictionary
@export var td: Dictionary[String, float] = {}
```
```
[resource]
script = ExtResource("1_qs4lt")
td = Dictionary[String, float]({
"test_data": 1.0,
"test_data_2": 9999.0
})
metadata/_custom_type_script = "uid://cl70yrd06uwft"
```
After the change:
```gdscript
extends Resource
class_name ResourceWithTypedDictionary
@export var td: Dictionary[String, Variant] = {}
```
```
[resource]
script = ExtResource("1_qs4lt")
td = Dictionary[String, float]({
"string_not_float": "test data string",
"test_data": 1.0,
"test_data_2": 9999.0
})
metadata/_custom_type_script = "uid://cl70yrd06uwft"
```
### Steps to reproduce
1. Create a custom resource script like this
```gdscript
extends Resource
class_name ResourceWithTypedDictionary
@export var td: Dictionary[String, float] = {}
```
2. Create a resource file from the script
3. Put some data inside the dictionary of the resource file
4. Save everything
5. Change dictionary value type from `float` to `Variant` in the script
6. Put `String` data in the dictionary
7. Run a scene which has a script that uses the created resource
8. Observe the error
### Minimal reproduction project (MRP)
There is git repo initialized and the first commit contains changes before changing dictionary's value type. Uncommited changes is what happened after the change.
[typed-dictionary-reource-type-change.zip](https://github.com/user-attachments/files/21168221/typed-dictionary-reource-type-change.zip)
Contributor guide
Research direction
Start with core/variant/dictionary.cpp around assign() at line 509, then reproduce the issue with the attached typed-dictionary resource project. Compare the serialized resource before and after changing the dictionary value type to Variant, and run the scene to observe the conversion error. Done means the changed resource no longer retains the old float value type or produces the reported assignment failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, godot
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100