godotengine / godotengine/godot

After parser error, exported members become null (or NodePaths become empty)

Open
#94,504 4 comments 2 reactions 0 assignees View on GitHub
bug discussion topic:editor topic:gdscript
Dominant language
C++
Stars
117k
Forks
26.8k
PR merge metrics
PR metrics pending

Description

### Tested versions

- Reproducible in: v4.2.1.stable.official [b09f793f5]

### System information

Godot v4.2.1.stable - Ubuntu 22.04.4 LTS 22.04 - X11 - Vulkan (Mobile) - dedicated NVIDIA GeForce GTX 860M (nvidia; 535.161.07) - Intel(R) Core(TM) i7-4710HQ CPU @ 2.50GHz (8 Threads)

### Issue description

While I'm working on a script, I generally reach a state where the script becomes invalid, such as messing up with indentation or removing used variables. This causes a temporary Parser Error, which is not a big deal.

However, I found out that in some situations, this will cause a bunch of members on nodes using my script to suddenly become null (I generally use scene instances, if that matters).

![Boss members became null](https://github.com/user-attachments/assets/c0ed481c-4221-4297-8579-7971dadda6f3)

```tscn
max_horizontal_speed = null
deceleration_time = null
slide_speed = null
```

I don't know the exact circumstances to reproduce the bug, but since it has happened many times and is the main reason why I need to restart Godot (along with spurious persistent parser errors that stay cached until I restart), and found so similar bug here, I decided to open one. Unfortunately this is hard to reproduce specifically when you want to, on simple code; it just happens if you work on a project long enough, on code that is complex enough... But I hope that having an issue will allow developers to start can discussing this and share MWE.

The possible actions needed to cause the bug are:
- try to play the game (this may force a save in some invalid state, causing members to become null)
- work with instantiated scenes with the script attached
- use inheritance on script and trigger the parser error somewhere on the class hierarchy

**Variant**: instead of null, the members containing NodePath become all cleared to empty NodePaths

![PlayerCharacter after restart and resave gets short NodePath but still empty](https://github.com/user-attachments/assets/896e7009-2307-4d22-a9fd-6502ba8db245)

```tscn
attack_input_buffer_timer = NodePath("")
body_collision_shape_standing = NodePath("")
body_collision_shape_crouching = NodePath("")
...
```

And today I got, for the first time, the very weird super complex serialization made of many empty NodePaths:

![level_boss_tiny after parser error gets weird super long serialized empty NodePath](https://github.com/user-attachments/assets/cdbff65d-c75f-41a9-91cc-d7078ef1ee85)

```tscn
body_collision_shape_standing = Object(CollisionShape2D,"_import_path":NodePath(""),"unique_name_in_owner":false,"process_mode":0,"process_priority":0,"process_physics_priority":0,"process_thread_group":0,"editor_description":"","visible":true,"modulate":Color(1, 1, 1, 1),"self_modulate":Color(1, 1, 1, 1),"show_behind_parent":false,"top_level":false,"light_mask":1,"visibility_layer":1,"z_index":2,"z_as_relative":true,"y_sort_enabled":false,"texture_filter":0,"texture_repeat":0,"material":null,"use_parent_material":false,"position":Vector2(0, 0.5),"rotation":0.0,"scale":Vector2(1, 1),"skew":0.0,"shape":null,"disabled":false,"one_way_collision":false,"one_way_collision_margin":1.0,"script":null)

body_collision_shape_crouching = Object(CollisionShape2D,"_import_path":NodePath(""),"unique_name_in_owner":false,"process_mode":0,"process_priority":0,"process_physics_priority":0,"process_thread_group":0,"editor_description":"","visible":true,"modulate":Color(1, 1, 1, 1),"self_modulate":Color(1, 1, 1, 1),"show_behind_parent":false,"top_level":false,"light_mask":1,"visibility_layer":1,"z_index":2,"z_as_relative":true,"y_sort_enabled":false,"texture_filter":0,"texture_repeat":0,"material":null,"use_parent_material":false,"position":Vector2(0, 2),"rotation":0.0,"scale":Vector2(1, 1),"skew":0.0,"shape":null,"disabled":false,"one_way_collision":false,"one_way_collision_margin":1.0,"debug_color":Color(0.792157, 0.427451, 0, 0.419608),"script":null)

animation_controller = Object(Node,"_import_path":NodePath(""),"unique_name_in_owner":false,"process_mode":0,"process_priority":1,"process_physics_priority":0,"process_thread_group":0,"editor_description":"","script":Resource("res://Scripts/Animation/AnimationControllerPlayerCharacter.gd"),"player_character":Object(CharacterBody2D,"_import_path":NodePath(""),"unique_name_in_owner":false,"process_mode":0,"process_priority":0,"process_physics_priority":0,"process_thread_group":0,"editor_description":"","visible":true,"modulate":Color(1, 1, 1, 1),"self_modulate":Color(1, 1, 1, 1),"show_behind_parent":false,"top_level":false,"light_mask":1,"visibility_layer":1,"z_index":0,"z_as_relative":true,"y_sort_enabled":false,"texture_filter":0,"texture_repeat":0,"material":null,"use_parent_material":false,"position":Vector2(99, 124),"rotation":0.0,"scale":Vector2(1, 1),"skew":0.0,"disable_mode":0,"collision_layer":256,"collision_mask":31,"collision_priority":1.0,"input_pickable":false,"motion_mode":0,"up_direction":Vector2(0, -1),"velocity":Vector2(0, 0),"slide_on_ceiling":true,"max_slides":4,"wall_min_slide_angle":0.261799,"floor_stop_on_slope":true,"floor_constant_speed":true,"floor_block_on_wall":true,"floor_max_angle":0.785398,"floor_snap_length":1.0,"platform_on_leave":0,"platform_floor_layers":4294967295,"platform_wall_layers":0,"safe_margin":0.08,"script":Resource("res://Scripts/Character/PlayerCharacter.gd"),"attack_input_buffer_timer":Object(Timer,"_import_path":NodePath(""),"unique_name_in_owner":false,"process_mode":0,"process_priority":0,"process_physics_priority":0,"process_thread_group":0,"editor_description":"","process_callback":0,"wait_time":0.1,"one_shot":true,"autostart":false,"script":null)
,"body_collision_shape_standing":Object(CollisionShape2D,"_import_path":NodePath(""),"unique_name_in_owner":false,"process_mode":0,"process_priority":0,"process_physics_priority":0,"process_thread_group":0,"editor_description":"","visible":true,"modulate":Color(1, 1, 1, 1),"self_modulate":Color(1, 1, 1, 1),"show_behind_parent":false,"top_level":false,"light_mask":1,"visibility_layer":1,"z_index":2,"z_as_relative":true,"y_sort_enabled":false,"texture_filter":0,"texture_repeat":0,"material":null,"use_parent_material":false,"position":Vector2(0, 0.5),"rotation":0.0,"scale":Vector2(1, 1),"skew":0.0,"shape":null,"disabled":false,"one_way_collision":false,"one_way_collision_margin":1.0,"script":null)
...
```

(cool, GitHub recognizes tscn syntax!)

after modifying some field to make the scene dirty and resave, it turned back to just simple empty NodePaths as in the previous screenshot

### Steps to reproduce

1. Create some script hierarchy and scene instances with some of those scripts
2. Modify script to cause a parser error... exact conditions unknown
3. Try to play the game anyway
4. Check the VCS for diff

### Minimal reproduction project (MRP)

Call for help!

It's probably easier to repro on a complex, existing project. Unfortunately the project where I just reproduced the bug is private, but if I can repro on a public one I can just share the repo with you and tell you what I did last. I invite other developers to do the same.

Contributor guide

Open the contributing guide

Research direction

Start with the listed reproduction steps: script inheritance, instantiated scenes, a parser error, and attempting to play the game. Compare the VCS scene diff for null exported members, empty NodePaths, or expanded Object serialization. Done means producing a minimal reproduction and identifying a reliable failure path; no source files or tests are named.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
game-dev, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.