{"record":{"id":"20b1cd0689f32e1e","repo":"Unity-Technologies/UnityCsReference","slug":"could-not-create-a-valid-delegate-from-method-mark","errorCode":null,"errorMessage":"Could not create a valid delegate from method marked: [RootEditorAttribute] with signature: ({signature})","messagePattern":"Could not create a valid delegate from method marked: \\[RootEditorAttribute\\] with signature: \\((.+?)\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Editor/Mono/Inspector/Core/RootEditor.cs","lineNumber":154,"sourceCode":"                    desc.usesMetaData = false;\n                    desc.rootEditorHandler = handler;\n                    rootEditors.Add(desc);\n                }\n                else if (Delegate.CreateDelegate(typeof(RootEditorWithMetaDataHandler), candidate, false) is RootEditorWithMetaDataHandler handlerWithMetaData)\n                {\n                    desc.usesMetaData = true;\n                    desc.rootEditorWithMetaDataHandler = handlerWithMetaData;\n                    rootEditorsWithMetaData.Add(desc);\n                }\n                else\n                {\n                    var parameters = candidate.GetParameters();\n                    var signature = parameters is { Length: > 0 }\n#pragma warning disable UA2001 // The Banned API Analyzer produces compile errors for any new Linq code. This pre-existing usage has been suppressed, but should be rewritten if possible.\n                        ? string.Join(\", \", parameters.Select(p => p.ParameterType.FullName))\n#pragma warning restore UA2001\n                        : string.Empty;\n                    throw new InvalidOperationException($\"Could not create a valid delegate from method marked: [{nameof(RootEditorAttribute)}] with signature: ({signature})\");\n                }\n            }\n\n            kSRootEditor.Clear();\n\n            // Adding the root editors with metadata first to take precedence over the general version\n            kSRootEditor.AddRange(rootEditorsWithMetaData);\n            kSRootEditor.AddRange(rootEditors);\n\n            ListPool<RootEditorDesc>.Release(rootEditors);\n            ListPool<RootEditorDesc>.Release(rootEditorsWithMetaData);\n        }\n    }\n}\n","sourceCodeStart":136,"sourceCodeEnd":169,"githubUrl":"https://github.com/Unity-Technologies/UnityCsReference/blob/225b0fbdb57cc17d094e8056b71f8314aba56f73/Editor/Mono/Inspector/Core/RootEditor.cs#L136-L169","documentation":"When registering root editors, the code tries to build either a plain handler or a metadata handler from a method marked [RootEditorAttribute]. If neither delegate construction path succeeds, it captures the method's parameter signature and throws InvalidOperationException, so a mis-signed handler fails loudly at registration rather than silently never firing.","triggerScenarios":"A method decorated with [RootEditorAttribute] has a parameter list that matches neither the expected root-editor delegate nor the metadata variant (e.g. wrong parameter types, wrong count, missing required context parameter).","commonSituations":"Authoring a custom root editor handler with an incorrect signature. Refactoring a handler and changing its parameters without updating the attribute contract. Copy-pasting a handler pattern from a different Unity version whose delegate signature differs.","solutions":["Match the exact delegate signature expected by RootEditorAttribute (inspect the accepted handler/metadata-handler parameter types in the registration code above the throw).","Ensure parameters are passed by the types the attribute expects (e.g. the metadata variant needs the metadata argument type).","Remove [RootEditorAttribute] from methods that are not intended to be root editor handlers.","Check the thrown signature string to see exactly which parameter types were rejected."],"exampleFix":"// before: signature mismatch -> InvalidOperationException with the printed signature\n[RootEditor] static void MyHandler(GameObject go, int extra) { } // wrong params\n\n// after: match the expected delegate parameter shape\n[RootEditor] static void MyHandler(RootEditorContext ctx) { }","handlingStrategy":"validation","validationCode":"// before attributing a method, verify it matches an accepted handler signature\nvar ps = method.GetParameters();\nbool ok = ps.Length == 0 || HandlerParameterTypes.Any(t => ps.Length == 1 && ps[0].ParameterType == t);\nif (!ok) return; // skip rather than register a bad handler","typeGuard":"static bool IsValidRootEditorSignature(MethodInfo m)\n{\n    var p = m.GetParameters();\n    return p.Length == 0 || (p.Length == 1 && IsAcceptedContextType(p[0].ParameterType));\n}","tryCatchPattern":null,"preventionTips":["Keep [RootEditor]-marked methods to the documented delegate signatures.","When refactoring handlers, re-read the registration code to confirm the accepted parameter types.","Avoid speculative attribute application; remove the attribute if a method is not a real handler."],"tags":["root-editor","delegate","attribute","reflection","signature"],"backgroundTag":null,"analyzedSha":"225b0fbdb57cc17d094e8056b71f8314aba56f73","analyzedAt":"2026-08-13T19:07:19.849Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}