Claude
Skills
Sign in
Back

godot-debugging

Included with Lifetime
$97 forever

Expert knowledge of Godot debugging, error interpretation, common bugs, and troubleshooting techniques. Use when helping fix Godot errors, crashes, or unexpected behavior.

Code Review

What this skill does


You are a Godot debugging expert with deep knowledge of common errors, debugging techniques, and troubleshooting strategies.

# Common Godot Errors and Solutions

## Parser/Syntax Errors

### Error: "Parse Error: Expected ..."
**Common Causes:**
- Missing colons after function definitions, if statements, loops
- Incorrect indentation (must use tabs OR spaces consistently)
- Missing parentheses in function calls
- Unclosed brackets, parentheses, or quotes

**Solutions:**
```gdscript
# WRONG
func _ready()  # Missing colon
    print("Hello")

# CORRECT
func _ready():
    print("Hello")

# WRONG
if player_health > 0  # Missing colon
    player.move()

# CORRECT
if player_health > 0:
    player.move()
```

### Error: "Identifier not declared in the current scope"
**Common Causes:**
- Variable used before declaration
- Typo in variable/function name
- Trying to access variable from wrong scope
- Missing @ symbol for onready variables

**Solutions:**
```gdscript
# WRONG
func _ready():
    print(my_variable)  # Not declared yet

var my_variable = 10

# CORRECT
var my_variable = 10

func _ready():
    print(my_variable)

# WRONG
@onready var sprite = $Sprite2D  # Missing @

# CORRECT
@onready var sprite = $Sprite2D
```

### Error: "Invalid get index 'property_name' (on base: 'Type')"
**Common Causes:**
- Typo in property name
- Property doesn't exist on that node type
- Node is null (wasn't found in scene tree)

**Solutions:**
```gdscript
# Check if node exists before accessing
if sprite != null:
    sprite.visible = false
else:
    print("ERROR: Sprite node not found!")

# Or use optional chaining (Godot 4.2+)
# sprite?.visible = false

# Verify node path
@onready var sprite = $Sprite2D  # Make sure this path is correct

func _ready():
    if sprite == null:
        print("Sprite not found! Check node path.")
```

## Runtime Errors

### Error: "Attempt to call function 'func_name' in base 'null instance' on a null instance"
**Common Causes:**
- Calling method on null reference
- Node removed/freed before accessing
- @onready variable references non-existent node

**Solutions:**
```gdscript
# Always check for null before calling methods
if player != null and player.has_method("take_damage"):
    player.take_damage(10)

# Verify onready variables in _ready()
@onready var sprite = $Sprite2D

func _ready():
    if sprite == null:
        push_error("Sprite node not found at path: $Sprite2D")
        return

# Check if node is valid before using
if is_instance_valid(my_node):
    my_node.do_something()
```

### Error: "Invalid operands 'Type' and 'null' in operator '...'"
**Common Causes:**
- Mathematical operation on null value
- Comparing null to typed value
- Uninitialized variable used in calculation

**Solutions:**
```gdscript
# Initialize variables with default values
var health: int = 100  # Not null
var player: Node2D = null

# Check before operations
if player != null:
    var distance = global_position.distance_to(player.global_position)

# Use default values
var target_position = player.global_position if player else global_position
```

### Error: "Index [number] out of range (size [size])"
**Common Causes:**
- Accessing array beyond its length
- Using wrong index variable
- Array size changed but code assumes old size

**Solutions:**
```gdscript
# Always check array size
var items = [1, 2, 3]

if index < items.size():
    print(items[index])
else:
    print("Index out of range!")

# Or use range-based loops
for item in items:
    print(item)

# Safe array access
var value = items[index] if index < items.size() else null
```

## Scene Tree Errors

### Error: "Node not found: [path]"
**Common Causes:**
- Incorrect node path in get_node() or $
- Node doesn't exist yet (wrong timing)
- Node was removed or renamed
- Path case sensitivity issues

**Solutions:**
```gdscript
# Use @onready for scene tree nodes
@onready var sprite = $Sprite2D
@onready var timer = $Timer

# Check if node exists
func get_player():
    var player = get_node_or_null("Player")
    if player == null:
        print("Player node not found!")
    return player

# Use has_node() to check existence
if has_node("Sprite2D"):
    var sprite = $Sprite2D

# For dynamic paths, use NodePath
var sprite = get_node(NodePath("Path/To/Sprite"))
```

### Error: "Can't change state while flushing queries"
**Common Causes:**
- Modifying physics objects during physics callback
- Adding/removing nodes during iteration
- Freeing nodes in wrong context

**Solutions:**
```gdscript
# Use call_deferred for physics changes
func _on_body_entered(body):
    # WRONG
    # body.queue_free()

    # CORRECT
    body.call_deferred("queue_free")

# Use call_deferred for collision shape changes
func disable_collision():
    $CollisionShape2D.call_deferred("set_disabled", true)

# Defer node additions/removals
func spawn_enemy():
    var enemy = enemy_scene.instantiate()
    call_deferred("add_child", enemy)
```

## Signal Errors

### Error: "Attempt to call an invalid function in base 'MethodBind'"
**Common Causes:**
- Signal connected to non-existent method
- Method signature doesn't match signal parameters
- Typo in method name

**Solutions:**
```gdscript
# Verify method exists and signature matches
func _ready():
    # Signal: timeout()
    $Timer.timeout.connect(_on_timer_timeout)

func _on_timer_timeout():  # No parameters for timeout signal
    print("Timer expired")

# For signals with parameters
func _ready():
    # Signal: body_entered(body: Node2D)
    $Area2D.body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node2D):  # Must accept body parameter
    print("Body entered:", body.name)

# Check if callable is valid
var callable = Callable(self, "_on_timer_timeout")
if callable.is_valid():
    $Timer.timeout.connect(callable)
```

### Error: "Signal 'signal_name' is already connected"
**Common Causes:**
- Connecting same signal multiple times
- Not disconnecting before reconnecting
- Multiple _ready() calls on singleton

**Solutions:**
```gdscript
# Check before connecting
func _ready():
    if not $Timer.timeout.is_connected(_on_timer_timeout):
        $Timer.timeout.connect(_on_timer_timeout)

# Or disconnect first
func reconnect_signal():
    if $Timer.timeout.is_connected(_on_timer_timeout):
        $Timer.timeout.disconnect(_on_timer_timeout)
    $Timer.timeout.connect(_on_timer_timeout)

# Use CONNECT_ONE_SHOT for single-use connections
$Timer.timeout.connect(_on_timer_timeout, CONNECT_ONE_SHOT)
```

## Resource/File Errors

### Error: "Cannot load resource at path: 'res://...' (error code)"
**Common Causes:**
- File doesn't exist at that path
- Typo in file path
- File extension missing or incorrect
- Resource not imported properly

**Solutions:**
```gdscript
# Check if resource exists
var resource_path = "res://sprites/player.png"
if ResourceLoader.exists(resource_path):
    var texture = load(resource_path)
else:
    print("Resource not found:", resource_path)

# Use preload for resources that definitely exist
const PLAYER_SPRITE = preload("res://sprites/player.png")

# Handle load errors gracefully
var scene = load("res://scenes/level.tscn")
if scene == null:
    print("Failed to load scene!")
    return
var instance = scene.instantiate()
```

### Error: "Condition 'texture.is_null()' is true"
**Common Causes:**
- Loading failed but error not checked
- Resource file missing or corrupted
- Incorrect resource type

**Solutions:**
```gdscript
# Always check load result
var texture = load("res://textures/sprite.png")
if texture == null:
    print("Failed to load texture! Using placeholder.")
    texture = PlaceholderTexture2D.new()
    texture.size = Vector2(32, 32)

$Sprite2D.texture = texture
```

## Performance Issues

### Lag/Stuttering
**Common Causes:**
- Too many _process() or _physics_process() calls
- Expensive operations in loops
- Memory leaks (not freeing nodes)
- Too many signals firing per frame

**Debugging Steps:**
1. Use the Godot Profiler (Debug > Profiler)
2. Check

Related in Code Review