godotengine / godotengine/godot

Unable to correctly save resource with typed dictionary after changing concrete value type to Variant

Open
#108,488 2 comments 0 reactions 0 assignees View on GitHub
bug topic:core topic:gdscript
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.