{"record":{"id":"4f9cd1d88e7593c4","repo":"stride3d/stride","slug":"this-method-can-only-be-called-during-step-step","errorCode":null,"errorMessage":"This method can only be called during step [{step}]","messagePattern":"This method can only be called during step \\[(.+?)\\]","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Rendering/Rendering/Materials/MaterialGeneratorContext.cs","lineNumber":620,"sourceCode":"                }\n                stageContext.Streams.Clear();\n\n                // Squash all ShaderSources to a single shader source\n                var materialBlendLayerMixin = stageContext.ComputeShaderSource();\n                stageContext.ShaderSources.Clear();\n\n                // Add the shader to the mixin\n                shaderMixinSource.AddComposition(\"layer\", materialBlendLayerMixin);\n\n                // Squash the shader sources\n                stageContext.ShaderSources.Add(shaderMixinSource);\n            }\n        }\n\n        private void EnsureStep(MaterialGeneratorStep step)\n        {\n            if (Step != step)\n                throw new InvalidOperationException($\"This method can only be called during step [{step}]\");\n        }\n    }\n}\n","sourceCodeStart":602,"sourceCodeEnd":624,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Rendering/Rendering/Materials/MaterialGeneratorContext.cs#L602-L624","documentation":"MaterialGeneratorContext exposes methods (AddShaderSource, SetMultiplePasses, callbacks, stream modifiers) that are only valid while the material compilation is inside a specific MaterialGeneratorStep. EnsureStep compares the context's current Step with the required step and throws InvalidOperationException when they differ. This guards the pipeline against calling phase-specific APIs out of order.","triggerScenarios":"Calling MaterialGeneratorContext.AddShaderSource/HasShaderSources outside the ShaderSourceGenerator step, SetMultiplePasses outside the MultiplePasses step, or AddFinalCallback/SetStreamFinalModifier/GetStreamFinalModifier outside the Finalize step (e.g. from a custom material pass or plugin invoked at the wrong stage).","commonSituations":"Writing a custom IMaterialGenerator or MaterialPass that calls stream/shader APIs in its constructor or in the wrong override; calling these APIs from a different thread or after Prepare/Build has advanced past the expected step.","solutions":["Move the API call (AddShaderSource, SetMultiplePasses, AddFinalCallback, etc.) into the code that runs during the corresponding MaterialGeneratorStep","If inside a generator, verify you are overriding/executing the correct step's method rather than an earlier/later one","Check whether the context has already been advanced (e.g. Prepare called twice or reused across passes) and use a fresh context if so"],"exampleFix":"// before (in Initialize / wrong phase)\ncontext.AddShaderSource(typeof(MyShader));\n// after (inside ProcessMaterialGenerator with step == MaterialGeneratorStep.ShaderSourceGenerator)\npublic override void Generate(MaterialGeneratorContext context)\n{\n    context.EnsureStep(MaterialGeneratorStep.ShaderSourceGenerator); // ensure correct phase\n    context.AddShaderSource(typeof(MyShader));\n}","handlingStrategy":"validation","validationCode":"// ensure the context is in the expected step before calling phase-specific APIs\nif (context.Step != MaterialGeneratorStep.ShaderSourceGenerator)\n    throw new InvalidOperationException($\"AddShaderSource requires step {MaterialGeneratorStep.ShaderSourceGenerator}, current: {context.Step}\");","typeGuard":"static bool InStep(MaterialGeneratorContext ctx, MaterialGeneratorStep step) => ctx.Step == step;","tryCatchPattern":"try { context.AddShaderSource(typeof(MyShader)); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"This method can only be called during step\")) {\n    logger.Warn(\"Material generator API called in wrong step; skipped\");\n}","preventionTips":["Call step-specific MaterialGeneratorContext APIs only inside the matching override of your material generator","Never cache the context across phases or frames","Write custom generators by copying the step order of built-in generators"],"tags":["rendering","materials","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}