# 5 Things AI Gets Wrong When Writing Godot 4 Code (And How to Catch Them)

> AI-generated Godot 4 code looks right and breaks. Five common mistakes we catch on every PR, why they look right, and how a reviewer fixes them.

AI can write Godot code fast. It can also write Godot 3 code in a Godot 4 project, hallucinate APIs that don't exist, move physics bodies in the wrong callback, and wire signals with patterns the engine deprecated two years ago.

The problem isn't that AI is bad at Godot. The problem is that AI is confidently wrong about Godot in ways that look right if you don't already know the engine. The code compiles. The game runs. Then something breaks at the worst possible time and you can't figure out why.

Godot's own maintainers have flagged this. AI-generated pull requests to the engine itself have become [a recurring drain on maintainers](https://www.gamedeveloper.com/programming/godot-co-founder-says-ai-slop-pull-requests-have-become-overwhelming), with maintainers questioning whether contributors even understand or tested their code. If that's happening on the engine's own repo, it's happening on yours too.

These are the five most common mistakes we see in AI-generated Godot code, caught during code review. Each example includes what the AI wrote, why it looks right, why it breaks, and what a reviewer should catch.

*Note: Examples below are reproduced test cases based on patterns we consistently catch across Godot repos. They represent real categories of AI mistakes, demonstrated on test fixtures.*

---

## 1. Godot 3.x movement code in a Godot 4 project

**What the AI writes:**

```gdscript
extends KinematicBody2D

var velocity = Vector2.ZERO

func _physics_process(delta):
    velocity = move_and_slide(velocity, Vector2.UP)
```

**Why it looks right:** This is textbook Godot 3 movement. Every tutorial from 2020 to 2022 teaches it exactly this way. The structure is clean, the variable names make sense, and if you're new to Godot, nothing looks wrong.

**Why it breaks:** `KinematicBody2D` was renamed to `CharacterBody2D` in Godot 4. `move_and_slide()` no longer takes arguments. Instead, it reads from the node's built-in `velocity` property. The [official migration guide](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.html) lists this as a major breaking change.

**What a reviewer should catch:** Wrong node type. Wrong method signature. The project will fail with class and method errors around `KinematicBody2D` and `move_and_slide()`, but if the change is buried in a larger PR, the connection to a Godot 3/4 rename won't be obvious to someone who doesn't know about the migration.

**The fix:**

```gdscript
extends CharacterBody2D

func _physics_process(delta):
    velocity = Vector2.ZERO  # set before input handling
    # ... input logic ...
    move_and_slide()
```

---

## 2. Hallucinated or renamed APIs

**What the AI writes:**

```gdscript
var marker = Position2D.new()
var sprite = Sprite.new()
```

**Why it looks right:** `Position2D` and `Sprite` are real Godot classes. They existed for years. They show up in thousands of tutorials, Stack Overflow answers, and forum threads.

**Why it breaks:** Both were renamed in Godot 4. `Position2D` became `Marker2D`. `Sprite` became `Sprite2D`. The old names don't exist. The [migration docs](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.html) list dozens of renames like this. AI models trained on pre-4.0 content will confidently use the old names.

**What a reviewer should catch:** Any node class name that doesn't appear in the Godot 4.x class reference. Surmado Code Review cross-references diffs against the current Godot documentation, so renamed classes get flagged automatically.

---

## 3. Physics movement in `_process()` instead of `_physics_process()`

**What the AI writes:**

```gdscript
extends CharacterBody2D

func _process(delta):
    velocity.x = Input.get_axis("left", "right") * speed
    move_and_slide()
```

**Why it looks right:** The code uses the correct Godot 4 node and method. The input handling is clean. `delta` is available. It runs.

**Why it breaks:** `_process()` runs every rendered frame. `_physics_process()` runs at a fixed rate (60 times per second by default). Moving a `CharacterBody2D` in `_process()` causes inconsistent movement speed across different hardware, jitter during frame drops, and unreliable collision detection. The [official docs](https://docs.godotengine.org/en/stable/tutorials/scripting/idle_and_physics_processing.html) are explicit: physics-related work belongs in `_physics_process()`.

**What a reviewer should catch:** Any `move_and_slide()`, `move_and_collide()`, or direct velocity manipulation inside `_process()`. This is the most dangerous of the five mistakes because the code works in testing and only fails under real conditions.

---

## 4. String-based signal connections

**What the AI writes:**

```gdscript
func _ready():
    $Button.connect("pressed", self, "_on_button_pressed")
```

**Why it looks right:** This is how signals worked in Godot 3. Tutorials, courses, and YouTube walkthroughs teach this pattern extensively.

**Why it breaks:** Godot 4 uses callable-based signal connections. The three-argument `connect()` with string method names is deprecated. The new syntax is:

```gdscript
func _ready():
    $Button.pressed.connect(_on_button_pressed)
```

The old style may still work in some cases but loses compile-time validation. If you rename the method later, the string connection silently breaks at runtime instead of erroring at parse time. The [Godot 4 Signal docs](https://docs.godotengine.org/en/stable/getting_started/step_by_step/signals.html) recommend the callable form.

**What a reviewer should catch:** Any `.connect("signal_name", target, "method_name")` pattern in a Godot 4 project. It's a reliable marker of AI-generated code sourced from outdated tutorials.

---

## 5. Unity-style assumptions and brittle scene tree paths

**What the AI writes:**

```gdscript
func _ready():
    var hud = get_parent().get_node("HUD")
    var player = get_node("../../Player")
    health_bar = get_node("../UI/HealthBar")
```

**Why it looks right:** It works if the scene tree looks exactly the way the code assumes. The paths resolve. The nodes exist.

**Why it breaks:** Godot's architecture is built around composable scenes that can be instanced anywhere. Hardcoded parent and sibling paths assume a fixed tree structure. Move the node, reparent the scene, or reuse it in a different context and the paths break silently. The practical rule in Godot is ["call down, signal up"](https://kidscancode.org/godot_recipes/4.x/): children access their own children directly, and communicate upward through signals. Parent and sibling access should use exported references or group queries, not hardcoded paths.

**What a reviewer should catch:** `get_parent()`, `get_node("..")`, or any path that navigates upward in the tree. These are brittle by design, and they're a pattern AI imports from Unity's component model where `GetComponentInParent` is common and expected.

---

## Why linters don't catch this

Godot's built-in warning system and tools like `gdscript-toolkit` catch formatting, unused variables, and some type issues. They're useful and you should use them.

But they don't catch wrong-version APIs in a Godot 4 project. They don't catch `_process()` vs. `_physics_process()` misuse. They don't know that your STANDARDS.MD says "no parent path navigation" or "always use callable signal connections." Those are review-level catches, not lint-level catches.

That's the gap automated code review fills. It sits between the linter (which checks syntax) and the human reviewer (who checks architecture), and it handles the middle layer: is this code correct for this engine version, these standards, and this project?

## Catching these in every PR

[Surmado Code Review for Godot](https://www.surmado.com/review/godot) runs on every push to a GitHub pull request. It checks the diff against the official Godot 4.6 documentation, your repo context, and your STANDARDS.MD. It catches:

- Cross-version mistakes (Godot 3 patterns in Godot 4 projects)
- Hallucinated or renamed APIs
- Lifecycle misuse (`_process` vs. `_physics_process`)
- Deprecated signal patterns
- Brittle scene tree assumptions
- Whatever else you define in your standards

Free for 10 PRs a month. $15/month for 100. No per-seat pricing.

If you're building a Godot game with AI assistance, the AI is the author. You need a different brain as the reviewer.

---

*[Install Surmado Code Review for Godot (Free) →](https://www.surmado.com/review/godot)*

*New to Godot? [Ask GDScout](https://games.surmado.com) anything about Godot 4.6 in plain English. Free, with citations from the official docs.*

## Questions and Answers

**What is the best AI code review tool for Godot?**
Surmado Code Review for Godot is an automated PR reviewer that checks diffs against official Godot 4.6 documentation, repo context, and a team's STANDARDS.MD. It catches cross-version mistakes (Godot 3 patterns in Godot 4 projects), hallucinated APIs, lifecycle misuse, deprecated signal patterns, and brittle scene tree assumptions. Free for 10 PRs per month, $15 per month for 100 PRs.

**What are common AI mistakes in Godot 4 code?**
The most common AI-generated mistakes in Godot 4 code include using renamed Godot 3 node types (KinematicBody2D instead of CharacterBody2D), passing arguments to move_and_slide() which no longer accepts them in Godot 4, placing physics movement in _process() instead of _physics_process(), using deprecated string-based signal connections instead of callable-based connections, and hardcoding parent/sibling node paths that break when scenes are reused.

**Does Surmado Code Review work with GDScript?**
Yes. Surmado Code Review supports GDScript and C# in Godot projects. Reviews are grounded in the official Godot 4.6 documentation and flag engine-specific issues that general-purpose AI code review tools miss.

**How is Surmado Code Review different from a GDScript linter?**
GDScript linters and Godot's built-in warning system catch syntax errors, formatting issues, unused variables, and some type problems. Surmado Code Review catches higher-level issues: wrong-version APIs, lifecycle callback misuse, deprecated patterns, brittle scene tree architecture, and violations of the team's STANDARDS.MD. Linters and code review are complementary. Linters enforce rules. Code review evaluates context.

**Can AI-generated Godot code pass linting but still be wrong?**
Yes. AI-generated Godot code frequently passes linting and compiles without errors but contains incorrect engine version patterns, lifecycle callback misuse, or scene tree assumptions that cause runtime failures. For example, placing CharacterBody2D movement in _process() instead of _physics_process() will lint, compile, and run, but produces inconsistent behavior across different hardware and frame rates.
