{"record":{"id":"9235ae49d332db10","repo":"stride3d/stride","slug":"trying-to-end-a-function-which-was-not-started","errorCode":null,"errorMessage":"Trying to end a function which was not started","messagePattern":"Trying to end a function which was not started","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Functions.cs","lineNumber":32,"sourceCode":"        var func = context.Bound++;\n        foreach (var t in ftype.ParameterTypes)\n            context.GetOrRegister(t.Type);\n        context.AddName(func, name);\n        var result = new SpirvFunction(func, name, ftype) { IsStage = isStage };\n        return result;\n    }\n\n    public void BeginFunction(SpirvContext context, SpirvFunction function, FunctionControlMask mask = FunctionControlMask.None)\n    {\n        Buffer.Add(new OpFunction(context.GetOrRegister(function.FunctionType.ReturnType), function.Id, mask, context.GetOrRegister(function.FunctionType)));\n        Position = Buffer.Count;\n        CurrentFunction = function;\n    }\n\n    public void EndFunction()\n    {\n        if (CurrentFunction is null)\n            throw new InvalidOperationException(\"Trying to end a function which was not started\");\n\n        // If there was no explicit return, add one\n        var lastInstruction = Buffer[Position - 1];\n        if (!IsBlockTermination(lastInstruction.Op))\n        {\n            if (CurrentFunction.Value.FunctionType.ReturnType != ScalarType.Void)\n                throw new InvalidOperationException(\"No function termination, but a return value is expected\");\n\n            Return(null);\n        }\n\n        Buffer.Insert(Position++, new OpFunctionEnd());\n    }\n\n    public SpirvValue EmitFunctionParameter(SpirvContext context, string name, SymbolType type)\n    {\n        var p = Buffer.Insert(Position++, new OpFunctionParameter(context.GetOrRegister(type), context.Bound++));\n        context.AddName(p, name);","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Functions.cs#L14-L50","documentation":"EndFunction finalizes the SPIR-V function currently being built. It throws InvalidOperationException when CurrentFunction is null, i.e. EndFunction was called without a matching StartFunction — the builder's function stack is empty.","triggerScenarios":"Calling EndFunction() when no function was started, calling it twice for the same function, or an exception earlier in emission skipped StartFunction while cleanup still calls EndFunction.","commonSituations":"Unbalanced Start/End pairs in shader code generators, exception paths that partially emit a function, or refactored emit pipelines where a helper now starts the function conditionally.","solutions":["Ensure every EndFunction call is paired with exactly one earlier StartFunction.","Guard the EndFunction call: only call it if CurrentFunction is not null.","In error/finally paths, check builder state before finalizing.","Log function start/end pairs during development to detect imbalance."],"exampleFix":"// before\nbuilder.EndFunction();\n// after\nif (builder.CurrentFunction is not null)\n    builder.EndFunction();","handlingStrategy":"validation","validationCode":"if (builder.CurrentFunction is null) return; // nothing to end","typeGuard":"bool canEndFunction = builder.CurrentFunction is not null;","tryCatchPattern":"try { builder.EndFunction(); } catch (InvalidOperationException ex) { /* unbalanced Start/EndFunction — audit emit pipeline */ throw; }","preventionTips":["Strictly pair StartFunction/EndFunction calls","Guard cleanup/finally paths with a null check","Avoid calling EndFunction twice for the same function","Track function scope in the generator state machine"],"tags":["spirv","shader-compiler","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-23T08:17:48.524Z"}