{"record":{"id":"be8fb28afd11c285","repo":"stride3d/stride","slug":"could-not-find-a-load-operation-right-before-interop-pin","errorCode":null,"errorMessage":"Could not find a load operation right before Interop.Pin","messagePattern":"Could not find a load operation right before Interop\\.Pin","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.AssemblyProcessor/InteropProcessor.cs","lineNumber":180,"sourceCode":"        else if (previousInstruction.OpCode == OpCodes.Ldloc_2)\n        {\n            variableIndex = 2;\n        }\n        else if (previousInstruction.OpCode == OpCodes.Ldloc_3)\n        {\n            variableIndex = 3;\n        }\n        else if (previousInstruction.OpCode == OpCodes.Ldloc_S)\n        {\n            variableIndex = ((VariableReference)previousInstruction.Operand).Index;\n        }\n        else if (previousInstruction.OpCode == OpCodes.Ldloc)\n        {\n            variableIndex = ((VariableReference)previousInstruction.Operand).Index;\n        }\n        else\n        {\n            throw new InvalidOperationException(\"Could not find a load operation right before Interop.Pin\");\n        }\n\n        var variable = ilProcessor.Body.Variables[variableIndex];\n        variable.VariableType = variable.VariableType.MakePinnedType();\n\n        ilProcessor.Remove(previousInstruction);\n        ilProcessor.Remove(fixedtoPatch);\n    }\n\n    private void ReplaceFixedStatement(MethodDefinition method, ILProcessor ilProcessor, Instruction fixedtoPatch)\n    {\n        var paramT = ((GenericInstanceMethod)fixedtoPatch.Operand).GenericArguments[0];\n        // Preparing locals\n        // local(0) T& pinned\n        method.Body.Variables.Add(new VariableDefinition(new PinnedType(new ByReferenceType(paramT))));\n\n        int index = method.Body.Variables.Count - 1;\n","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.AssemblyProcessor/InteropProcessor.cs#L162-L198","documentation":"InteropProcessor's ReplacePinStatement rewrites Interop.Pin patterns expecting the instruction immediately before it to load a value into a local (ldloc/ldloca or constant/ldarga form). When the previous instruction is not any recognized load, it throws this InvalidOperationException because the pin pattern is malformed.","triggerScenarios":"PatchMethod encounters an Interop.Pin call whose preceding IL is not a load operation (e.g. the pinned value comes from a call, field load, or reordered stack operations).","commonSituations":"Writing custom pinning code whose IL shape differs from the patterns Interop.Pin expects; compiler updates (new Roslyn emit patterns) changing instruction order; chaining expressions so the pinned value isn't a simple local load.","solutions":["Restructure the pinned code so the value is stored to and loaded from a local variable before Interop.Pin","Extract complex expressions into a local first (e.g. var ptr = obj.Field; fixed(...)) so the IL becomes a simple ldloc","Avoid calling Interop.Pin directly on computed/call results; pin simple locals","Update Stride version if a newer compiler's IL pattern is unsupported"],"exampleFix":"// before\nInterop.Pin(obj.Inner.Value, out handle); // previous IL is a call/ldfld, not ldloc\n// after\nvar v = obj.Inner.Value;\nInterop.Pin(v, out handle); // previous IL is ldloc.0","handlingStrategy":"validation","validationCode":"// ensure pinned value is a local: if you cannot write `var v = expr; Interop.Pin(v, ...)` the IL will not match","typeGuard":null,"tryCatchPattern":"// build-time: catch in AssemblyProcessor task logs\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"load operation right before Interop.Pin\"))\n{\n    // restructure the pinning code to use a local variable\n}","preventionTips":["Pin simple local variables only, not call/field results","Follow Stride's documented Interop.Pin usage pattern","Test AssemblyProcessor output after compiler upgrades"],"tags":["il-weaving","interop","pinning","assemblyprocessor"],"backgroundTag":"internal-invariant-violation","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"}