stride3d/stride · error · InvalidOperationException
Missing forward lighting render feature
Error message
Missing forward lighting render feature
What it means
After finding a MeshRenderFeature, LightShafts.InitializeCore also requires a ForwardLightingRenderFeature nested within it, because it needs that feature's ShadowMapRenderer to render light shafts. It throws InvalidOperationException when the ForwardLightingRenderFeature is absent. The pipeline meshes but uses a different lighting strategy (e.g. deferred), so light shafts cannot obtain shadow data.
Solutions
- Add a ForwardLightingRenderFeature as a child feature of the MeshRenderFeature in your RenderSystem configuration.
- If using deferred lighting, remove LightShafts or implement/port it for your lighting feature.
- Verify with code: meshRenderFeature.RenderFeatures.OfType<ForwardLightingRenderFeature>().Any() before enabling light shafts.
Example fix
// before var meshFeature = new MeshRenderFeature(); // no lighting sub-feature // after var meshFeature = new MeshRenderFeature(); meshFeature.RenderFeatures.Add(new ForwardLightingRenderFeature());
Defensive patterns
Strategy: validation
Validate before calling
var mesh = Context.RenderSystem.RenderFeatures.OfType<MeshRenderFeature>().FirstOrDefault();
if (mesh == null || !mesh.RenderFeatures.OfType<ForwardLightingRenderFeature>().Any())
throw new InvalidOperationException("LightShafts requires ForwardLightingRenderFeature under MeshRenderFeature"); Try / catch
try { EnableLightShafts(scene); }
catch (InvalidOperationException e) { Log.Warning($"Light shafts unavailable with current lighting pipeline: {e.Message}"); } Prevention
- When migrating to deferred lighting, audit and remove forward-only effects like LightShafts.
- Always add ForwardLightingRenderFeature as a child of MeshRenderFeature in setup code.
- Check for ForwardLightingRenderFeature presence before enabling shadow-dependent effects.
When it happens
Trigger: A compositor whose MeshRenderFeature does not include ForwardLightingRenderFeature (deferred lighting pipeline or custom lighting features), while a LightShafts renderer is enabled in the scene.
Common situations: Switching a project from forward to deferred lighting and leaving light shafts enabled; custom lighting render features replacing the stock forward one.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- Custom strides is not supported with packed PixelFormats
- Missing mesh render feature
- A region can only be specified for Textures with…
- A texture with size [ ] already exist with the same output…
- A UIPage asset can't have more than one root.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/d473ad4905a41aa1.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Rendering/Rendering/Images/LightShafts/LightShafts.cs:96
lightShaftsEffectShader = ToLoadAndUnload(new ImageEffectShader("LightShaftsEffect"));
// Additive blending shader
applyLightEffectShader = ToLoadAndUnload(new ImageEffectShader("AdditiveLightEffect"));
applyLightEffectShader.BlendState = new BlendStateDescription(Blend.One, Blend.One);
minmaxVolumeEffectShader = new DynamicEffectInstance("VolumeMinMaxShader");
minmaxVolumeEffectShader.Initialize(Context.Services);
blur = ToLoadAndUnload(new GaussianBlur());
// Need the shadow map renderer in order to render light shafts
var meshRenderFeature = Context.RenderSystem.RenderFeatures.OfType<MeshRenderFeature>().FirstOrDefault();
if (meshRenderFeature == null)
throw new InvalidOperationException("Missing mesh render feature");
var forwardLightingFeature = meshRenderFeature.RenderFeatures.OfType<ForwardLightingRenderFeature>().FirstOrDefault();
if (forwardLightingFeature == null)
throw new InvalidOperationException("Missing forward lighting render feature");
shadowMapRenderer = forwardLightingFeature.ShadowMapRenderer;
for (int i = 0; i < 2; ++i)
{
var minmaxPipelineState = new MutablePipelineState(Context.GraphicsDevice);
minmaxPipelineState.State.SetDefaults();
minmaxPipelineState.State.BlendState.RenderTargets[0].BlendEnable = true;
minmaxPipelineState.State.BlendState.RenderTargets[0].ColorSourceBlend = Blend.One;
minmaxPipelineState.State.BlendState.RenderTargets[0].ColorDestinationBlend = Blend.One;
minmaxPipelineState.State.BlendState.RenderTargets[0].ColorBlendFunction = i == 0 ? BlendFunction.Min : BlendFunction.Max;
minmaxPipelineState.State.BlendState.RenderTargets[0].ColorWriteChannels = i == 0 ? ColorWriteChannels.Red : ColorWriteChannels.Green;
minmaxPipelineState.State.DepthStencilState.DepthBufferEnable = false;
minmaxPipelineState.State.DepthStencilState.DepthBufferWriteEnable = false;
minmaxPipelineState.State.RasterizerState.DepthClipEnable = true;
minmaxPipelineState.State.RasterizerState.CullMode = i == 0 ? CullMode.Back : CullMode.Front;View on GitHub (pinned to 96fad776d2)