{"record":{"id":"a7dafc8a7d7254ef","repo":"stride3d/stride","slug":"error-when-generating-update-engine-code-for-0","errorCode":null,"errorMessage":"Error when generating update engine code for {0}","messagePattern":"Error when generating update engine code for (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.AssemblyProcessor/UpdateEngineProcessor.cs","lineNumber":194,"sourceCode":"        {\n            // Special case: when processing Stride.Engine assembly, we automatically add dependent assemblies types too\n            if (!serializableType.Value.Local && strideEngineAssembly != context.Assembly)\n                continue;\n\n            if (serializableType.Key is not TypeDefinition typeDefinition)\n                continue;\n\n            // Ignore already processed types\n            if (!processedTypes.Add(typeDefinition))\n                continue;\n\n            try\n            {\n                ProcessType(context, module.ImportReference(typeDefinition), mainPrepareMethod);\n            }\n            catch (Exception e)\n            {\n                throw new InvalidOperationException(string.Format(\"Error when generating update engine code for {0}\", typeDefinition), e);\n            }\n        }\n\n        // Force generic instantiations — register resolvers for lists, arrays, and trigger generic update methods\n        // Generates calls like:\n        //   UpdateEngine.RegisterMemberResolver(new ListUpdateResolver<ElementType>());\n        //   UpdateEngine.RegisterMemberResolver(new ArrayUpdateResolver<ElementType>());\n        //   ParameterCollectionResolver.InstantiateValueAccessor<KeyType>();  // iOS AOT only\n        //   UpdateGeneric_TypeName<T1, T2>();  // for closed generic types\n        var il = new ILBuilder(mainPrepareMethod.Body, module);\n        foreach (var serializableType in context.SerializableTypesProfiles.SelectMany(x => x.Value.SerializableTypes).ToArray())\n        {\n            // Special case: when processing Stride.Engine assembly, we automatically add dependent assemblies types too\n            if (!serializableType.Value.Local && strideEngineAssembly != context.Assembly)\n                continue;\n\n            // Try to find if original method definition was generated\n            var typeDefinition = serializableType.Key.Resolve();","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.AssemblyProcessor/UpdateEngineProcessor.cs#L176-L212","documentation":"UpdateEngineProcessor.ProcessSerializers generates update-engine member code for each serializable type via ProcessType. If ProcessType throws for a type, the exception is wrapped in this InvalidOperationException naming the TypeDefinition, preserving the root cause as InnerException.","triggerScenarios":"ProcessType fails while emitting IL for a type's updatable members — e.g. unsupported member types, methods with unexpected signatures for [Updater]/UpdateEngine conventions, or an earlier serializer error surfacing during engine codegen.","commonSituations":"A class implementing UpdateEngine interfaces whose member/update method signatures don't match expectations; a type whose serializer generation already failed upstream; stride source-level changes to updatable conventions.","solutions":["Read the InnerException to find the exact member/signature that failed","Align the type's update methods with the expected UpdateEngine signatures","Annotate unsupported members appropriately or exclude the type from update-engine processing","Fix any preceding serializer-generation errors for the type first"],"exampleFix":"// before\nclass Enemy : IUpdate\n{\n    public void Update(int dt, object extra) {} // wrong signature\n}\n// after\nclass Enemy : IUpdate\n{\n    public void Update(int dt) {} // matches expected signature\n}","handlingStrategy":"try-catch","validationCode":"// Validate updatable types conform to UpdateEngine conventions before processing:\nforeach (var m in typeof(Enemy).GetMethods())\n    if (m.Name == \"Update\" && m.GetParameters().Length > 1)\n        Console.WriteLine($\"[warn] {m} does not match expected Update signature\");","typeGuard":"static bool MatchesUpdateSignature(MethodInfo m) =>\n    m.Name == \"Update\" && m.GetParameters().All(p => p.ParameterType.IsPrimitive || p.ParameterType.IsValueType);","tryCatchPattern":"try { ProcessSerializers(types); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Error when generating update engine code\"))\n{\n    logger.Error($\"{ex.Message} -- inner: {ex.InnerException?.Message}\");\n}","preventionTips":["Keep update methods exactly matching UpdateEngine-expected signatures","Fix serializer-generation errors for the type before engine codegen","Inspect InnerException first — this error is always a wrapper"],"tags":["update-engine","codegen","il-emit"],"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"}