Quick answer: Run the exported binary from a terminal with --verbose to see the real shader error. Most editor-versus-export discrepancies come from missing highp/mediump qualifiers, unexported .gdshaderinc files, or Compatibility-renderer feature limitations.
Your custom dissolve shader looks great in the editor preview. You hit Export, send the build to a tester, and they report a magenta error material on every object. The editor said the shader was fine. The runtime disagrees.
Why the Editor and Export Disagree
Godot’s shader language (.gdshader) is translated to the target platform’s native shader language at runtime: GLSL ES 3.0 for Compatibility/web, GLSL 4.5 for Forward+, MSL on Metal, SPIR-V on Vulkan. The editor uses one renderer (commonly Forward+) and the export may use another (Compatibility for web/mobile). The translation rules and the underlying driver compiler differ between renderers, so a shader that translates cleanly to Vulkan SPIR-V may fail in the GLSL ES 3.0 emitter or be rejected by an Adreno driver.
Step 1: Get the Real Error Message
Open a terminal and launch the exported binary with verbose logging:
# Linux/macOS
./MyGame.x86_64 --verbose 2>&1 | tee shader-log.txt
# Windows (cmd)
MyGame.exe --verbose > shader-log.txt 2>&1
# Android
adb logcat -c && adb shell am start -n com.you.game/.GodotApp
adb logcat | grep -i godot
The output contains lines like:
ERROR: Shader compilation failed.
At: res://shaders/dissolve.gdshader:14
ERROR: ‘noise_uv’ : undeclared identifier
That filename and line number is the entire investigation. The editor compiled against a different backend and never saw this error.
Step 2: Add Missing Precision Qualifiers
GLES 3.0 requires every float uniform and varying to have a precision qualifier. Forward+ doesn’t. Compatibility/web targets fail when qualifiers are missing:
// Fails in Compatibility
uniform float intensity;
// Works everywhere
uniform highp float intensity;
Use highp for positions, time, and values needing full precision; mediump for colors and UVs; lowp for sentinel-like values. Apply to varyings too.
Step 3: Check Export Filters for .gdshaderinc
If your shader uses #include, the included .gdshaderinc files must be exported. Open Project → Export → Resources and ensure either “Export all resources in the project” is selected or the “Filters to export non-resource files” field includes *.gdshaderinc.
Verify after export by inspecting the PCK:
# Extract the PCK and grep for include files
godot --headless --extract MyGame.pck
find . -name "*.gdshaderinc"
Step 4: Verify Compatibility-Renderer Feature Use
The Compatibility renderer does not support: 3D arrays, texture_sample_grad, texelFetch on multisample textures, and shader storage buffers. If your shader uses any of these and the export targets web or low-end mobile, the translation step produces a compile error.
Test by switching the editor renderer to Compatibility (Project Settings → Rendering → Renderer, then restart) and reload the shader. Any error you see in the editor under Compatibility will also appear at runtime in a Compatibility export.
Step 5: Validate on the Target Driver
Even with correct GLSL, vendor drivers reject shaders the spec considers valid. Qualcomm Adreno is the most common offender for highp handling on Android. Build a test scene with the shader applied to a quad, push the APK to a representative device, and watch logcat. Catching driver-specific failures before release means deploying to at least one device per major GPU family (Adreno, Mali, PowerVR, Apple, Intel, AMD, NVIDIA).
Verifying
Re-export with verbose logging enabled. Search the log for “Shader compilation failed” — if absent, the shader compiled. Visually verify the effect at runtime; if the material renders correctly but you still see “Shader needs SPIR-V conversion” warnings, those are informational and not actually errors.
“The editor lies. The runtime tells the truth. Run the export from a terminal — the answer is in stdout.”
Test under Compatibility renderer in the editor before exporting for web or mobile.