Article

Why your AI-generated Unity code compiles, runs, and doesn't work

Unity games built with AI tools come together quickly, and the first couple of weeks are genuinely impressive. I’ve been watching what happens after that, and the pattern is consistent enough to be worth writing down. The prototype works. The demo goes well. Then things start breaking, and not with compile errors.

The code compiles, runs, and silently doesn’t work.

Here’s why, and none of it is really a knock on the tools. Every failure below comes from the same place: the tool was asked about something it couldn’t see, and answered anyway. That’s a description of where the information is, not a measure of how good the tool is.

1. AI can’t read your scene

Most projects store scenes and prefabs (.unity, .prefab) as YAML, so they are text, and a text-based tool can open them. What it finds there is not the scene: objects are 19-digit fileIDs, scripts are GUIDs that only resolve through a separate .meta file, and a modest scene runs to tens of thousands of lines of it. (Serialisation is a project setting, so some studios do run Force Binary or Mixed, in which case there is nothing to open at all.) Either way, when you ask an agent to “add a feature that interacts with the player object”, it has no working view of your scene hierarchy. It infers one from the names it saw in your scripts, which is a reasonable thing to do with the information available.

The result: scripts that reference GameObjects, tags, or component types that don’t exist. The code compiles because the types are valid C#. It runs because Unity doesn’t validate scene references at compile time. It fails at runtime: NullReferenceException, or worse, silent failure where the feature just doesn’t trigger.

You paste the error back. It infers again, from the same missing information.

Opening the scene and checking the hierarchy answers it in about thirty seconds. That option isn’t available to something reading only the text files, and no amount of improvement to the model changes that, because it isn’t a reasoning problem.

2. Three input systems, one silent bug

Unity has three input systems:

  • The old Input Manager (Input.GetKey)
  • The new Input System package (InputAction)
  • Device-specific APIs

Nothing in your C# says which one the project is set to, so a tool reaches for whichever it has seen most. I watched someone spend an hour on broken input after two systems got mixed. The code compiled. It ran. Input just didn’t work.

The fix is one setting: Edit → Project Settings → Player → Active Input Handling → Both. That’s the sort of thing you learn once and then never forget. The tool never mentioned it, and not because it couldn’t have. Nobody asked.

This is the pattern: AI doesn’t tell you what you don’t know. It answers the question you asked, not the question you should have asked.

3. List mutation: when “correct” code corrupts data

I audited a Unity game where AI implemented poker hand matching. The code looked correct. It passed code review. It had a subtle bug: cards.Reverse() was called on a list that was shared across all hand-checking iterations.

List<T>.Reverse() mutates the list in place. Every subsequent hand check received the reversed list, silently producing wrong results for any hand that cared about order.

The fix is to take a reversed copy instead of reversing the shared list. That is fiddlier than it sounds, because cards is a List<T> and C# resolves instance methods before extension methods: cards.Reverse() binds to List<T>.Reverse(), which returns void, so chaining .ToList() onto it doesn’t even compile. You have to reach past the instance method, with Enumerable.Reverse(cards).ToList() or cards.AsEnumerable().Reverse().ToList(). The AI didn’t know the difference between List<T>.Reverse() (in-place mutation) and Enumerable.Reverse() (new sequence), and the call site gives you no hint which one you got.

This bug didn’t crash. It didn’t throw. It produced wrong scores, and the player would never know why. You catch it if you’ve been burned by List<T>.Reverse() before, which is the whole of it: not intelligence, just a scar.

4. The revert cycle

In the same project, AI broke working input. Had to revert. AI broke working cell selection. Had to revert. AI introduced a “direction lock” that was more sophisticated than needed and broke basic selection. Had to revert.

At one point the only honest summary of the build was “the game loads again, but is broken”. The game was broken, the AI made changes, and the game was still broken, just differently.

Each improvement broke something else. Every one of them was a reasonable answer to the prompt it was given, and the prompt was the whole world: nothing in it described the system the change was landing in, or which existing behaviour mattered.

5. Unfinished game

This project had a proper architecture: Instance/Object data-visual split, observer pattern, assembly definitions with GUIDs, functional error handling with Option<T>, service locator, UniTask async, editor validators. A senior engineer’s architecture.

And it still produced: silent data corruption, repeated breakage of working systems, duplicated reward logic, no audio, no haptics, no power-ups, no monetisation, no save system for complex state, and commented-out state transitions.

The game was left broken and unfinished.

The lesson

Worth being clear that this is the best case: a well-architected codebase with someone experienced reading every change. The architecture didn’t prevent any of it. What it did was make the damage findable, and even then it took a person reading the code to find it.

Take the same process without the data/visual split, without Option<T>, without assembly definitions, and without anyone catching the list mutation or the input system mix. The failures are the same ones. They’re just no longer local, and by the time they surface there are features built on top of them, which is the difference between a fix and a rewrite.


I audit and fix AI-generated Unity codebases. If your game works but changing it has become risky, I can tell you what’s broken, why, and what to do about it.

Read the full teardown


This article uses real code from a real project.

Your game works. Changing it is the part that has got harder.

A fixed-price audit tells you what's wrong, why it's wrong, and what to do about it.

Book a discovery call

[email protected] · replies within 1 business day