setget in Godot 4: Expected end of statement after variable declaration, found "Identifier" instead

By Eduardo Orellana · Updated

Godot 4 has no setget. Write the setter and getter on the variable itself: var health := 100: then an indented set(value): and get: block, or point at functions with var shield := 50: set = set_shield. The Godot 3 line var health = 100 setget set_health fails to parse with Expected end of statement after variable declaration, found "Identifier" instead.

What Godot is checking

The Godot 4 parser does not know setget. After var health = 100 it expects the end of the statement; it finds the word setget, an identifier, and reports that. The message does not mention setget, which is why it is hard to search for.

In Godot 4 the setter runs whenever the variable is assigned, from inside the class as well as from outside: Godot 3 skipped the setter for assignments inside the class unless you wrote self.health. Inside its own setter, assigning the variable stores the value directly, without calling the setter again.

Reproduce it

A Godot 3 property with setget in a Godot 4 project. The scene is one Node with this script.

extends Node

var health = 100 setget set_health

func set_health(value):
	health = clamp(value, 0, 100)

func _ready():
	self.health = 150
	print(health)

What Godot 4.7.2 prints

Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org

SCRIPT ERROR: Parse Error: Expected end of statement after variable declaration, found "Identifier" instead.
   at: GDScript::reload (res://answers/setget-in-godot-4/repro.gd:3)
ERROR: Failed to load script "res://answers/setget-in-godot-4/repro.gd" with error "Parse error".
   at: load (modules/gdscript/gdscript_resource_format.cpp:46)

Fix it

Both Godot 4 forms: health with an inline set and get, shield pointing at a named setter. The run assigns each from inside the class, and the setters run.

extends Node

var health := 100:
	set(value):
		health = clampi(value, 0, 100)
		print("health set to ", health)
	get:
		return health

var shield := 50: set = set_shield

func set_shield(value: int) -> void:
	shield = maxi(value, 0)

func _ready() -> void:
	health = 150
	health -= 30
	shield = -5
	print("health is ", health, ", shield is ", shield)

What the fixed script prints

Godot Engine v4.7.2.stable.mono.official.ed1daf0bf - https://godotengine.org

health set to 100
health set to 70
health is 70, shield is 0

Verified on Godot 4.7.2

Both scripts on this page were run headless on Godot 4.7.2 (4.7.2.stable.mono.official.ed1daf0bf) on 6 October 2026, and the output above is what Godot printed, unedited.

Where the check lives in Godot's source: [gdscript_parser.cpp line 695, the message](https://github.com/godotengine/godot/blob/4.7.2-stable/modules/gdscript/gdscript_parser.cpp#L695).

Questions

Why does my setter now run when I assign the variable inside the class?
Godot 4 calls the setter for every assignment, inside the class or outside, as the fixed run shows: health = 150 inside _ready printed health set to 100. Godot 3 called it from inside only for self.health.