Missing global shader X's permutation 0, Please make sure cooking was successful.

Hi!

We’ve added a custom shader to one of our plugins that apparently doesn’t get cooked. It works perfectly fine when in editor. When starting a cooked build it crashes with the following error:

00:56:00 [2025.04.22-17.27.32:227][ 0]LogOutputDevice: Error: Fatal error: [File:.\Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp] [Line: 4573] 00:56:00 [2025.04.22-17.27.32:227][ 0]LogOutputDevice: Error: Missing global shader FPL_JumpFloodPS's permutation 0, Please make sure cooking was successful.This isn’t the first custom shader in this plugin, the others appear to be working fine. There are no cooking errors.

The plugin consists of multiple modules. The base module does this in its StartupModule function:

void FPL_PostProcessingModule::StartupModule() { const FString& BaseDir = IPluginManager::Get().FindPlugin(TEXT("PL_PostProcessing"))->GetBaseDir(); const FString& PluginShaderDir = FPaths::Combine(BaseDir, TEXT("Shaders")); AddShaderSourceDirectoryMapping(TEXT("/PL_PostProcessing/Shaders"), PluginShaderDir); }

The shader in question is declared like this, in one of the other modules:

`class FPL_JumpFloodPS : public FGlobalShader
{
public:
DECLARE_GLOBAL_SHADER(FPL_JumpFloodPS);
SHADER_USE_PARAMETER_STRUCT(FPL_JumpFloodPS, FGlobalShader);

BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT(FScreenPassTextureViewportParameters, Viewport)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, InputSampler)
SHADER_PARAMETER(float, StepSize)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
};

IMPLEMENT_GLOBAL_SHADER(FPL_JumpFloodPS, “/PL_PostProcessing/Shaders/JumpFlood/JumpFlood.usf”, “JumpFloodPS”, SF_Pixel);`We don’t really have a lot to go on here, any help finding out if this shader is getting cooked, or why this shader isn’t getting cooked (or if it is getting cooked, what the errors could be)?

Ciao, Daniel!

Hello there,

Just to clarify, you are seeing this on a Windows Development, Test, or Shipping build?

This seems very similar to an issue I was looking into recently.

Best regards,

Chris

Hi!

First of all - I’m a dummy and found why this wasn’t working… solution at end.

The setup of this plugin is as follows:

PostProcessing (plugin)

PostProcessing (module, base system)

PostProcessingEffects (module, individual effects that use the base system)

There are also editor modules, but they don’t play into this.

I already had some simple helper shaders in the base module, and they worked fine.

Then I added a more complicated effect with a custom shader to the effects module, and that worked fine locally. However, after submitting it to our CI and trying any of the cooked test builds it spits out, they all crashed with the aforementioned missing global shader error.

I then spent a good day experimenting around, trying to simplify the shader, moving files around, and in the end determined that everything works fine as long as the FGlobalShader and IMPLEMENT_GLOBAL_SHADER stuff is in the base module, and not in the effects module. Which weirded me out, because it’s ugly, but it was an OK workaround.

And then when I cleaned up my perforce changelists, I saw what the actual issue was…

I had failed to submit the updated .uplugin file to the CI, which changed the LoadingPhase for the PostProcessingEffects module from Default to PostConfigInit.

When starting the editor, Unreal checks that and errors out, making it obvious what the issue is. But the cooker apparently doesn’t do that, and instead just silently ignores the shader. The Test build definitely doesn’t check this and just crashes out with a missing global shader.

So in the end, a classical ‘forgot to submit updated file’ error was the issue. What would definitely have helped here would have been if the cooker would also error out and inform that there’s a global shader in a module that is being loaded too late, just like the editor does.

Thanks,

Ciao, Daniel!

I’m very glad you got to the bottom of the issue.

Looks like the issue I was looking at is slightly different.

Best regards,

Chris