Corrigindo o Erro do UBA Executor no UBT em Source Builds da Unreal Engine no UE 5.8
Em resumo
Este guia explica a causa e a solução para o erro do UBA Executor no UBT que trava a compilação a partir do código-fonte no Unreal Engine 5.8. Analisamos como a falha ocorre durante chamadas recursivas do compilador ao tentar buildar utilitários como o UnrealHeaderTool. Apresentamos métodos práticos para resolver o problema, incluindo a configuração correta do arquivo BuildConfiguration.xml ou a aplicação de um patch no código C# da factory de executores. Por fim, compartilhamos boas práticas para otimizar o pipeline de compilação da engine e integrar servidores multiplayer.
Poucas coisas quebram o ritmo de um estúdio como uma build quebrada da engine, especialmente quando você está compilando a Unreal Engine 5.8.0 a partir do código-fonte e o Visual Studio trava com uma exceção enigmática. A build falha com uma exceção não tratada apontando diretamente para UBAExecutor.cs. Esse bloqueador específico, conhecido como o unreal engine uba executor ubt error, interrompe completamente a compilação. Ele impede que o build graph conclua a geração de programas auxiliares críticos como o UnrealHeaderTool. Neste guia, vamos detalhar por que o Unreal Build Accelerator (UBA) tem dificuldades com chamadas aninhadas, como a configuração padrão falha e como aplicar um patch no código-fonte da sua engine para restaurar um pipeline de build funcional.
Entendendo a Arquitetura do Build System
Para entender por que esse erro ocorre, precisamos examinar como o Unreal Build Tool (UBT) orquestra a compilação. As bases de código da Unreal Engine são massivas, frequentemente contendo dezenas de milhares de arquivos de código-fonte. Para compilá-los com eficiência, o UBT atua como um meta-build system, gerando grafos de dependência e despachando ações de compilação.
O que é o Unreal Build Accelerator?
A Epic Games introduziu o Unreal Build Accelerator (UBA) como o executor de compilação padrão para substituir sistemas de distribuição mais antigos. O UBA foi projetado para acelerar a compilação utilizando um sistema de arquivos virtualizado leve (VFS) para interceptar operações de I/O de arquivos. Ele roteia as tarefas do compilador entre múltiplos núcleos locais ou as distribui em nós de build do Horde.
Em uma máquina de build padrão de 64 núcleos, o UBA pode reduzir o tempo de compilação limpa da engine de aproximadamente 90 minutos para menos de 25 minutos. No entanto, como o UBA depende de um agente local centralizado para interceptar a E/S, ele exige um controle estrito sobre como os processos do compilador são gerados.
O mecanismo de Chamadas Recursivas do UBT
Durante uma execução de compilação, o UBT frequentemente encontra targets que precisam ser construídos antes que os binários principais da engine possam ser compilados. Por exemplo, antes de compilar o executável UnrealEditor, o UBT precisa compilar o UnrealHeaderTool (UHT) para analisar arquivos de cabeçalho (headers) e gerar metadados de reflexão.
Para conseguir isso, o processo primário do UBT gera um processo secundário e aninhado do UBT para compilar o target de pré-requisito. Essa invocação aninhada é chamada de chamada recursiva do UBT (recursive UBT call). Quando uma chamada recursiva do UBT está ativa, o UBT define uma flag interna (UnrealBuildTool.IsRecursive = true) e propaga variáveis de ambiente para marcar o processo como aninhado.
Por que o UBA Executor Falha em Invocações Recursivas
O crash ocorre porque o UBA executor não foi arquitetado para suportar loops de compilação aninhados. Vamos dar uma olhada na stack trace típica gerada pelo UBT quando essa falha ocorre no Visual Studio:
Unhandled exception: Exception: UBA executor is not expected to be invoked from a recursive UBT call.
at UnrealBuildTool.UBAExecutor.Init(IEnumerable`1 targetDescriptors, ILogger logger) in UnrealEngine\Engine\Source\Programs\UnrealBuildTool\Executors\UnrealBuildAccelerator\UBAExecutor.cs:line 315
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at UnrealBuildTool.UBAExecutor.ExecuteActionsAsync(IEnumerable`1 inputActions, ILogger logger) in UnrealEngine\Engine\Source\Programs\UnrealBuildTool\Executors\UnrealBuildAccelerator\UBAExecutor.cs:line 617
at UnrealBuildTool.ActionGraph.InternalExecuteActions(ActionExecutor Executor, List`1 ActionsToExecute, ILogger Logger) in UnrealEngine\Engine\Source\Programs\UnrealBuildTool\Actions\ActionGraph.cs:line 435
A Verificação de Segurança em UBAExecutor.cs
Dentro do método UBAExecutor.Init (por volta da linha 315 de UBAExecutor.cs), a engine impõe explicitamente uma verificação de segurança contra recursão:
// Engine/Source/Programs/UnrealBuildTool/Executors/UnrealBuildAccelerator/UBAExecutor.cs
public void Init(IEnumerable<TargetDescriptor> TargetDescriptors, ILogger Logger)
{
if (UnrealBuildTool.IsRecursive)
{
throw new Exception("UBA executor is not expected to be invoked from a recursive UBT call.");
}
// Virtualized file system and network initialization follow...
}
Essa verificação de segurança existe por um motivo crucial. O agente local do UBA se vincula a portas TCP específicas para se comunicar com os processos auxiliares virtualizados do compilador.
Se uma invocação recursiva do UBT tentasse inicializar uma segunda instância do UBA executor, ambas as instâncias tentariam se vincular aos mesmos sockets de rede e entrariam em conflito com os hooks do sistema de arquivos virtualizado. Isso levaria a erros de alocação de socket, corrupção do sistema de arquivos ou deadlocks indefinidos na build. A exceção serve como uma barreira de proteção.
A Causa Raiz: Falha na Seleção do Executor
O verdadeiro bug nas source builds da Unreal Engine 5.8.0 não é essa verificação de segurança. Na verdade, é a falha na lógica da factory de executores ao lidar corretamente com chamadas recursivas.
Quando o UBT determina qual executor usar, ele consulta a classe ExecutorFactory.cs. A factory verifica se o UBA está ativado e disponível na máquina hospedeira.
No entanto, ela não verifica se o processo atual do UBT é uma execução recursiva. Como resultado, quando o processo secundário do UBT é iniciado para compilar o UnrealHeaderTool, a factory tenta atribuir o UBAExecutor à build aninhada, disparando o crash no método Init.
A Armadilha da Configuração XML
Muitos desenvolvedores tentam contornar esse problema modificando o arquivo global BuildConfiguration.xml. O conselho padrão em posts antigos de fóruns é desativar o UBA desabilitando a seguinte tag:
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBA>false</bAllowUBA>
</BuildConfiguration>
</Configuration>
Por que bAllowUBA é Ignorado no UE 5.8
Se você aplicar a configuração XML acima a uma source build da Unreal Engine 5.8.0, o compilador ainda tentará iniciar o UBA e lançará a exceção. Isso ocorre porque o sistema de configuração de build da engine foi refatorado.
A antiga flag bAllowUBA foi descontinuada (deprecated) e não está mais mapeada para a lógica de seleção de executor. Em vez disso, o comportamento do UBA é controlado por duas propriedades distintas: bAllowUBAExecutor e bAllowUBALocalExecutor.
Como o UBT não encontra bAllowUBAExecutor no seu XML, ele assume true por padrão. Isso sobrescreve silenciosamente sua tentativa de desativar o UBA.
Estrutura XML Correta para Configuração do UBA
Para desativar o UBA com sucesso via arquivos de configuração, você deve usar os nomes de propriedades XML atualizados. Abaixo está a estrutura correta para forçar o UBT a usar os executores locais padrão (fallback):
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBAExecutor>false</bAllowUBAExecutor>
<bAllowUBALocalExecutor>false</bAllowUBALocalExecutor>
</BuildConfiguration>
</Configuration>
Essa configuração ignora o UBA com sucesso. No entanto, desativar o UBA inteiramente significa que você perderá os benefícios significativos de velocidade de compilação que ele oferece para suas ações de build principais.
Guia Passo a Passo para Corrigir o Erro
Dependendo do seu fluxo de trabalho, você pode optar por resolver esse problema globalmente modificando sua configuração XML ou aplicando um patch diretamente no código-fonte do UBT para preservar a aceleração de build para compilações não recursivas.
Método 1: Sobrescrita via BuildConfiguration.xml
Se você não quiser modificar o código-fonte da engine, pode desativar o UBA globalmente. Essa é a maneira mais rápida de fazer seu projeto compilar, embora vá aumentar os tempos de compilação para clean builds em cerca de 40% a 60%, dependendo do seu hardware.
- Localize ou crie seu arquivo global
BuildConfiguration.xml. No Windows, ele geralmente fica localizado em%AppData%\Roaming\Unreal Engine\UnrealBuildTool\BuildConfiguration.xml. No Linux, fica em~/.config/Unreal Engine/UnrealBuildTool/BuildConfiguration.xml. - Abra o arquivo XML em um editor de texto.
- Substitua o conteúdo pelo esquema XML atualizado mostrado abaixo.
- Salve o arquivo e reinicie sua build no Visual Studio.
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bAllowUBAExecutor>false</bAllowUBAExecutor>
<bAllowUBALocalExecutor>false</bAllowUBALocalExecutor>
</BuildConfiguration>
</Configuration>
Método 2: Patching do Código-Fonte do UBT (Recomendado)
Como você está compilando a Unreal Engine 5.8 a partir do código-fonte, a solução recomendada é aplicar um patch no código-fonte C# do UBT. Isso permite que o UBA rode no seu target primário de compilação, enquanto força um fallback para o ParallelExecutor padrão durante chamadas recursivas.
- Navegue até o diretório do código-fonte do UBT:
Engine/Source/Programs/UnrealBuildTool/Executors/. - Abra o arquivo
ExecutorFactory.csno Visual Studio ou em um editor de texto. - Localize o método
Create. Este método é responsável por avaliar sua configuração e retornar oActionExecutorapropriado. - Modifique a condicional de seleção do UBA para incluir uma verificação de execuções recursivas do UBT.
// Engine/Source/Programs/UnrealBuildTool/Executors/ExecutorFactory.cs
public static ActionExecutor Create(BuildConfiguration BuildConfiguration, List<TargetDescriptor> TargetDescriptors, ILogger Logger)
{
// Check if UBA is allowed, available, and NOT running recursively
- if (BuildConfiguration.bAllowUBAExecutor && UBAExecutor.IsAvailable())
+ if (BuildConfiguration.bAllowUBAExecutor && UBAExecutor.IsAvailable() && !UnrealBuildTool.IsRecursive)
{
return new UBAExecutor(BuildConfiguration, Logger);
}
// Fall back to IncrediBuild if configured
if (BuildConfiguration.bAllowXGE)
{
return new XGEExecutor(BuildConfiguration, Logger);
}
// Fall back to standard ParallelExecutor
return new ParallelExecutor(BuildConfiguration, Logger);
}
Esse patch evita que a instância aninhada do UBT selecione o UBA executor. Em vez disso, a build recursiva (como a compilação do UnrealHeaderTool) rodará com segurança usando o ParallelExecutor local, enquanto a compilação principal da engine continua a utilizar todo o poder do UBA.
Método 3: Flags de Linha de Comando
Se você estiver rodando seu processo de build através de scripts de linha de comando personalizados ou pipelines de CI/CD, você pode desativar o UBA por invocação. Isso é particulamente útil se você quiser manter o UBA ativado para desenvolvedores locais, mas desativá-lo em servidores de build remotos.
Para fazer isso, adicione a flag -NoUBA ao seu comando de build do UBT:
# Example command to build the editor without UBA
Engine\Build\BatchFiles\Build.bat UnrealEditor Win64 Development -NoUBA
Alternativamente, você pode forçar o UBT a usar o executor paralelo padrão especificando-o explicitamente com a flag -Executor:
Engine\Build\BatchFiles\Build.bat UnrealEditor Win64 Development -Executor=Parallel
Limpando e Regenerando o Ambiente de Build
Depois de aplicar qualquer uma das correções acima, o UBT pode falhar ao compilar devido a arquivos de assembly em cache ou metadados intermediários desatualizados. Para garantir que a correção funcione perfeitamente, você deve limpar os binários gerados da ferramenta de build e regenerar os arquivos de projeto.
Para Ambientes Windows
Execute os seguintes comandos em um prompt de comando ou instância do PowerShell apontando para o diretório raiz da Unreal Engine:
:: Delete the cached UBT assembly and build binaries
rd /s /q Engine\Intermediate\Build\UnrealBuildTool
rd /s /q Engine\Binaries\DotNET\UnrealBuildTool
:: Regenerate the project files
GenerateProjectFiles.bat
Para Ambientes Linux e macOS
Execute estes comandos no seu terminal:
# Remove cached build tool data
rm -rf Engine/Intermediate/Build/UnrealBuildTool
rm -rf Engine/Binaries/DotNET/UnrealBuildTool
# Regenerate project files
./GenerateProjectFiles.sh
Assim que o ambiente estiver limpo, abra o arquivo de solution gerado (UE5.sln) no Visual Studio e faça o rebuild do target. A build agora deve passar pela fase de compilação recursiva sem lançar a exceção de executor.
Boas Práticas Recomendadas para Source Builds da Unreal Engine
Compilar um fork customizado da engine a partir do código-fonte introduz vários desafios de compilação, otimização e empacotamento. A aplicação das seguintes boas práticas ajudará você a manter um pipeline de desenvolvimento estável e altamente otimizado.
1. Otimize a Concorrência para Evitar Memory Starvation
Compiladores C++ modernos exigem uma quantidade significativa de RAM por thread de compilação. Ao compilar grandes módulos da engine, o UBT pode iniciar mais tarefas paralelas do que a RAM do seu sistema suporta, levando a page-file thrashing ou crashes no compilador.
Você pode limitar a contagem máxima de processadores definindo as configurações do ParallelExecutor no seu arquivo BuildConfiguration.xml:
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<ParallelExecutor>
<MaxProcessorCount>16</MaxProcessorCount>
<ProcessorCountMultiplier>1.0</ProcessorCountMultiplier>
</ParallelExecutor>
</Configuration>
Limite a contagem para aproximadamente 2 GB de RAM por thread. Por exemplo, uma máquina com 32 GB de RAM deve limitar o MaxProcessorCount para 16.
2. Domine o Asset Stripping para Dedicated Server
Ao fazer o deploy do seu jogo na nuvem, você deve evitar compilar assets desnecessários do cliente (como texturas de UI, áudio e meshes) no binário do seu Dedicated Server. Isso reduz o tempo de inicialização do servidor e o footprint de memória, o que é crítico para escalar frotas com eficiência.
Para aprender a configurar seus scripts de build para excluir esses assets, siga nosso guia detalhado sobre Unreal Engine Dedicated Server Asset Stripping.
3. Verifique a Integridade de Blueprints e do Pacote Cedo
Uma build bem-sucedida da engine não garante que o seu projeto será empacotado sem erros. Blueprints desatualizados ou erros de serialização costumam causar crashes durante a fase final de empacotamento.
Para evitar que esses problemas bloqueiem seu pipeline de release, leia nosso guia sobre Resolving the Unreal Package HasValidBlueprint Ensure Crash para configurar verificações de validação automatizadas.
4. Configure o Caching do UBA VFS Corretamente
Se você decidir manter o UBA ativado usando o patch em C#, configure o cache do sistema de arquivos virtual para armazenar os arquivos de objeto compilados localmente. Isso evita a recompilação de arquivos-fonte não modificados ao alternar entre branches.
Adicione o bloco de configuração UnrealBuildAccelerator ao seu arquivo XML para ativar o caching:
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<UnrealBuildAccelerator>
<WriteCache>true</WriteCache>
<Cache>127.0.0.1</Cache>
</UnrealBuildAccelerator>
</Configuration>
Certifique-se de que seu firewall não bloqueie as portas de comunicação de rede local do UBA, que são usadas para gerenciar o loop de sincronização do cache.
Elevando a Arquitetura do seu Backend
Resolver problemas de compilação como o unreal engine uba executor ubt error é crucial para manter um fluxo de trabalho de desenvolvimento saudável. No entanto, configurar um ambiente de compilação local é apenas o primeiro passo na criação de um jogo multiplayer moderno.
Assim que sua engine customizada for compilada e seus dedicated servers estiverem prontos, você terá que enfrentar os desafios complexos da infraestrutura de backend. Escrever sua própria orquestração de servidores, algoritmos de matchmaking e bancos de dados de persistência do zero consome semanas de tempo de desenvolvimento.
Configurar load balancers, database sharding e gerenciamento de certificados SSL pode levar facilmente de 4 a 6 semanas de trabalho dedicado. Com o horizOn, esses serviços de backend vêm pré-configurados e prontos para escalar.
Em vez de escrever código de infraestrutura, você pode integrar dados de jogadores, lobbies em tempo real e escalonamento de servidores com poucas chamadas de API simples. Isso permite que você faça o deploy de builds de dedicated server e gerencie o estado do jogador com zero custo operacional de manutenção. Sua equipe pode focar nas mecânicas de gameplay e recursos da engine enquanto o horizOn cuida da infraestrutura em nuvem.
Próximos Passos
Para resolver esse erro de build, escolha entre a rápida sobrescrita via XML ou a aplicação do patch no código-fonte C# em ExecutorFactory.cs. Assim que seu pipeline de build estiver rodando sem problemas, procure maneiras de otimizar seu fluxo de deploy. Se você deseja escalar seu jogo multiplayer sem a complexidade de hospedar servidores customizados, experimente o horizOn gratuitamente ou confira nossa documentação da API para saber mais.