Voltar para o Blog
Quest Log

NullReferenceException na Unity: Como Achar e Corrigir

Janela de console de um editor de jogo com uma linha de erro vermelha destacada e um campo vazio no Inspector ao lado

Unity NullReferenceException: como ler o erro no Console, achar a linha, as causas mais comuns (Inspector, GetComponent, ordem, objeto destruído) e prevenir.

Ferramenta:UnityC#

NullReferenceException na Unity: Como Achar e Corrigir

Unity NullReferenceException ("Object reference not set to an instance of an object") quer dizer uma coisa só: o seu código tentou usar uma variável que vale null. Pode ser um campo que você esqueceu de arrastar no Inspector, um GetComponent que não achou o componente, um objeto que ainda não existia ou que já foi destruído. O Console diz o arquivo e a linha; a sua tarefa é descobrir qual variável daquela linha está vazia e por quê.

Este guia mostra como ler o erro e chegar na linha certa em segundos, passa pelas causas que mais aparecem em projeto de verdade (cada uma com o sintoma e a correção em C# para Unity 6.3 LTS), explica a diferença para UnassignedReferenceException e MissingReferenceException, e termina com hábitos que fazem esse erro quase sumir dos seus projetos.

Unity nullreferenceexception: o que significa

Em C#, variáveis de tipo referência (classes, componentes, GameObjects) guardam um endereço para um objeto. Quando não guardam nada, valem null. Declarar não cria o objeto:

private Rigidbody2D rb;

Essa linha cria uma variável vazia. Se o código chega em rb.linearVelocity = Vector2.zero; sem nunca ter posto um Rigidbody2D ali, a Unity lança NullReferenceException, porque não existe objeto para receber a velocidade.

O erro não é um bug da engine nem um problema de versão. É sempre uma pergunta sem resposta: "quem deveria ter preenchido essa variável, e quando?".

Ler o erro no Console e achar a linha

Uma mensagem típica:

NullReferenceException: Object reference not set to an instance of an object
PlayerHealth.TakeDamage (System.Int32 amount) (at Assets/Scripts/PlayerHealth.cs:23)
EnemyAttack.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/Scripts/EnemyAttack.cs:15)

Leia de cima para baixo:

  1. Primeira linha: o tipo do erro.
  2. Segunda linha: onde ele aconteceu. PlayerHealth.cs, linha 23, dentro de TakeDamage.
  3. Linhas seguintes: quem chamou. EnemyAttack chamou TakeDamage na linha 15.

Dê dois cliques na mensagem do Console e o editor de código abre na linha 23. Agora olhe todas as variáveis que aparecem antes de um ponto naquela linha. Em healthBar.fill.fillAmount = current / max;, os candidatos são healthBar e healthBar.fill. Um deles é null.

Para descobrir qual, ponha um log logo antes, usando o segundo parâmetro do Debug.Log:

Debug.Log("healthBar é null? " + (healthBar == null), this);

O segundo argumento é o contexto: ao clicar na mensagem no Console, a Unity destaca na Hierarchy o objeto que gerou o log. Isso resolve o caso clássico em que existem 30 inimigos e só um deles está com o campo vazio. Sem o contexto, você sabe que algum falhou; com ele, você sabe qual.

Causa 1: campo não arrastado no Inspector

A causa mais comum de todas. Você declara o campo, esquece de arrastar a referência e dá Play.

Arquivo PlayerHealth.cs:

using UnityEngine;
using UnityEngine.UI;

public class PlayerHealth : MonoBehaviour
{
    [SerializeField] private Image healthFill;
    [SerializeField] private int maxHealth = 100;

    private int currentHealth;

    private void Awake()
    {
        currentHealth = maxHealth;
    }

    public void TakeDamage(int amount)
    {
        currentHealth = Mathf.Max(currentHealth - amount, 0);
        healthFill.fillAmount = (float)currentHealth / maxHealth;
    }
}

Se healthFill ficou vazio no Inspector, a última linha falha. Aqui entra um detalhe da Unity: para campos serializados de tipos da Unity, você normalmente vê UnassignedReferenceException em vez de NullReferenceException, com uma mensagem bem mais útil, dizendo que a variável healthFill de PlayerHealth não foi atribuída e que você provavelmente precisa atribuí-la no Inspector. A correção é exatamente essa.

Atenção a dois casos que enganam:

  • Instância na cena preenchida, prefab vazio. Você preencheu o campo na instância que estava na cena, não no asset do prefab, e depois instanciou por código. Abra o prefab (duplo clique no Project) e preencha lá.
  • Dois componentes iguais no objeto. Um tem o campo preenchido e o outro não. O segundo gera o erro. Veja o Inspector inteiro.

Causa 2: GetComponent e Find retornando null

GetComponent<T>() devolve null quando o objeto não tem aquele componente. GameObject.Find("Nome") devolve null quando não existe objeto ativo com aquele nome, e o ponto "ativo" pega muita gente: Find não enxerga objeto desativado.

O jeito defensivo:

Arquivo EnemyAttack.cs:

using UnityEngine;

public class EnemyAttack : MonoBehaviour
{
    [SerializeField] private int damage = 10;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.TryGetComponent(out PlayerHealth health))
        {
            health.TakeDamage(damage);
        }
    }
}

TryGetComponent devolve false quando o componente não existe, então o código nunca toca numa referência nula. É também mais barato que GetComponent seguido de checagem, porque não aloca nada no editor quando falha.

Para componentes que o script exige, deixe a Unity garantir:

[RequireComponent(typeof(Rigidbody2D))]
public class PlayerMovement : MonoBehaviour

Com RequireComponent, adicionar o script adiciona o Rigidbody2D junto, e a Unity não deixa remover o componente enquanto o script estiver lá.

Sobre busca na cena: FindObjectOfType foi substituído na Unity 6 por FindFirstObjectByType e FindAnyObjectByType. Os dois devolvem null se não acharem nada. Use em inicialização, nunca dentro do Update, e sempre com checagem.

Até aqui você corrige um erro de cada vez. Num jogo com dezenas de scripts conversando, o que evita esses erros é arquitetura: quem cria quem, quem guarda referência a quem, quem avisa quem. Isso não aparece em tutorial de mecânica isolada, e é justamente o que o curso de Unity trabalha ao construir jogos completos, onde cada sistema precisa encontrar os outros sem quebrar.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Causa 3: ordem de execução

A Unity chama Awake de todos os objetos da cena antes de qualquer Start. Dentro de cada fase, a ordem entre scripts diferentes não é garantida. Um padrão que falha de forma intermitente:

  • GameManager.Awake faz Instance = this.
  • PlayerHud.Awake lê GameManager.Instance.score.

Às vezes o HUD roda primeiro, Instance ainda é null, e o erro aparece. Às vezes não. A regra que resolve: no Awake, cada script prepara a si mesmo; no Start, conversa com os outros. Mova a leitura do HUD para o Start e o problema some.

Se realmente precisar de ordem, existe Edit > Project Settings > Script Execution Order, ou o atributo [DefaultExecutionOrder(-100)] na classe que deve rodar antes. Use pouco; ordem forçada vira dívida quando o projeto cresce.

Causa 4: objeto destruído

Um inimigo guarda referência ao alvo. O alvo é destruído com Destroy(gameObject). No frame seguinte, o inimigo tenta ler target.position e recebe MissingReferenceException: o objeto foi destruído, mas o script ainda tenta acessá-lo.

A Unity tem uma comparação especial: um objeto destruído é igual a null quando testado com ==. Então a checagem funciona:

if (target != null)
{
    Vector3 direction = target.position - transform.position;
}

O que não funciona são os operadores ?. e ?? do C#. Eles olham a referência real, que ainda existe, e ignoram a comparação da Unity. target?.position num alvo destruído lança o erro do mesmo jeito. Com objetos da Unity (GameObject, componentes, ScriptableObject), use != null explícito.

Outra fonte frequente: evento assinado e não desassinado. O objeto é destruído na troca de cena, o evento estático continua chamando o método dele, e o método acessa o próprio transform. Assine no OnEnable e desassine no OnDisable, sempre em par.

Causa 5: prefab que precisa de objeto da cena

Você cria o prefab de um inimigo, e ele precisa saber onde está o jogador. Tenta arrastar o Player da Hierarchy no campo do prefab aberto, e a Unity não aceita. Não é bug: um asset de prefab existe fora de qualquer cena e não pode guardar referência a um objeto que só existe numa cena. Se o campo foi preenchido na instância que estava na cena, o inimigo funciona; os instanciados por código pelo spawner nascem com o campo vazio.

A correção é quem cria passar a referência. O spawner conhece o jogador (ele está na cena, então pode ter o campo arrastado) e entrega para cada inimigo logo depois do Instantiate. No spawner, o campo do prefab é tipado com o script do inimigo ([SerializeField] private EnemyChase enemyPrefab;), e o Instantiate devolve direto esse componente:

EnemyChase enemy = Instantiate(enemyPrefab, spawnPoint.position, Quaternion.identity);
enemy.Init(playerTransform);

Com um método Init(Transform target) público no inimigo, a dependência fica explícita: não existe inimigo sem alvo, e o erro, se acontecer, aparece no spawner, que é onde a referência faltou. É melhor que cada inimigo fazer FindFirstObjectByType sozinho, que esconde a dependência e custa caro com muitos inimigos.

UnassignedReferenceException e MissingReferenceException

As três exceções parecem iguais e apontam para causas diferentes:

ExceçãoQuando apareceOnde olhar
NullReferenceExceptionQualquer referência nula: variável nunca preenchida, GetComponent ou Find que não acharamA linha do erro e quem deveria ter preenchido a variável
UnassignedReferenceExceptionCampo serializado que ficou vazio no InspectorO Inspector do objeto citado na mensagem
MissingReferenceExceptionObjeto da Unity que já foi destruídoQuem chamou Destroy e quem ainda guarda a referência

Na prática, quando a mensagem é Unassigned, a correção quase sempre é arrastar algo no Inspector. Quando é Missing, a correção é de lógica: checar antes de usar ou limpar a referência quando o objeto morre.

Como prevenir

Hábitos que fazem esse erro quase sumir:

  • [SerializeField] private com validação no Awake. Se um campo obrigatório está vazio, avise com contexto e desligue o script, em vez de deixar quebrar no meio do jogo:
private void Awake()
{
    if (healthFill == null)
    {
        Debug.LogError("PlayerHealth sem healthFill em " + name, this);
        enabled = false;
    }
}
  • RequireComponent para dependências no mesmo objeto.
  • TryGetComponent para dependências opcionais ou de colisão.
  • Inicializar no Awake, conversar no Start.
  • Nada de ?. com objetos da Unity.
  • Ler o erro de cima para baixo antes de mudar código. Metade dos erros se resolve no Inspector.

Próximo passo

Na próxima vez que o Console ficar vermelho, faça o caminho completo: dois cliques, liste as variáveis da linha, log com contexto, ache a causa nesta lista. Se o erro for de objeto destruído, o post sobre MissingReferenceException na Unity aprofunda o caso. Para os tropeços que vão além deste erro, veja os erros mais comuns de iniciante em desenvolvimento de jogos, e se você também usa Godot, o guia de debug e erros comuns na Godot mostra o equivalente por lá.

Perguntas frequentes

O que significa "Object reference not set to an instance of an object" na Unity?

Significa que o código tentou usar uma variável que não aponta para nada, ou seja, que vale null. Acessar um campo, chamar um método ou ler uma propriedade de algo nulo lança NullReferenceException. A mensagem diz o arquivo e a linha onde isso aconteceu.

Qual a diferença entre NullReferenceException e UnassignedReferenceException?

UnassignedReferenceException é específica da Unity: aparece quando você usa um campo serializado que ficou vazio no Inspector, e a mensagem já diz qual campo e qual script. NullReferenceException é a exceção genérica do C# para qualquer referência nula, como um GetComponent que não achou nada.

O que é MissingReferenceException na Unity?

É o erro de usar um objeto que já foi destruído. A variável ainda guarda a referência, mas o objeto da Unity por trás dela não existe mais. A correção é checar com == null antes de usar ou deixar de guardar referência a objetos que podem ser destruídos.

Posso usar o operador ?. com objetos da Unity?

Não é recomendado. Os operadores ?. e ?? do C# ignoram a comparação especial da Unity, que faz um objeto destruído ser igual a null. Com eles, um objeto destruído passa pelo teste e o erro acontece do mesmo jeito. Use if (objeto != null) ou TryGetComponent.