Skip to content

Conversation

@ajara87
Copy link
Member

@ajara87 ajara87 commented Dec 3, 2025

Description

Improve plugin loading diagnostics by logging the assembly path when plugin type loading fails. Adding log in LoadPlugins and LoadPlugin

Change Log

  • Modify Plugin.cs class

Fixes # (issue)

Type of change

  • Optimization (the change is only an optimization)
  • Style (the change is only a code style for better maintenance or standard purpose)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • Unit Testing
  • Run Application
  • Local Computer Tests
  • No Testing

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@github-actions github-actions bot added the N3 label Dec 3, 2025
@ajara87
Copy link
Member Author

ajara87 commented Dec 3, 2025

Related to issue neo-project/neo-node#940

Copy link
Member

@vncoelho vncoelho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very good, @ajara87 , do you think we should set a config for neo-cli to make this log of this is good as default?

I will test asap

}

private static void LoadPlugin(Assembly assembly)
private static void LoadPlugin(Assembly assembly, string? sourcePath = null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assembly name is not enough?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's enough

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then please remove the sourcePath.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In most cases the assembly name is enough but in practice there are situations where multiple plugin DLLs share the same assembly name (for example, different versions or copies deployed under different plugin subfolders or mounted volumes).

In those cases the log becomes ambiguous if it only shows the assembly name. Including the file path in the log tells the operator exactly which physical DLL failed.

In this case It's just additional information but for me is ok I'll remove it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to test it right now and return to you guys

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR [11:18:20.520] 	Failed to load plugin assembly /opt/node/Neo.CLI/Plugins/SignClient/Grpc.Net.Client.dll
ERROR [11:18:20.540] 	System.TypeLoadException
Could not load type 'Grpc.Core.ConnectivityState' from assembly 'Grpc.Net.Common, Version=2.0.0.0,  Culture=neutral,  PublicKeyToken=d754f35622...in.cs:line  176
NEO-CLI v3.9.0  -  NEO v3.9.0  -  NEO-VM v3.9.0

neo> Unhandled exception. System.TypeInitializationException: The type initializer for 'Neo.NeoSystem' threw an exception.
 ---> System.TypeLoadException: Could not load type 'Grpc.Core.ConnectivityState' from assembly 'Grpc.Net.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad'.
   at System.Reflection.RuntimeAssembly.GetExportedTypes()
   at Neo.Plugins.Plugin.LoadPlugin(Assembly assembly, String sourcePath) in /opt/neo/src/Neo/Plugins/Plugin.cs:line 176
   at Neo.Plugins.Plugin.LoadPlugins() in /opt/neo/src/Neo/Plugins/Plugin.cs:line 228
   at Neo.NeoSystem..cctor() in /opt/neo/src/Neo/NeoSystem.cs:line 112
   --- End of inner exception stack trace ---
   at Neo.NeoSystem.CurrentDomain_UnhandledException(Object sender, UnhandledExceptionEventArgs e) in /opt/neo/src/Neo/NeoSystem.cs:line 185
   at System.AppContext.OnUnhandledException(Object e)
/opt/start_node.sh: line 2:    95 Aborted                 (core dumped) ( cd /opt/node/Neo.CLI/; dotnet neo-cli.dll )

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks make better @ajara87
It would be even better if we could print * dlls details as well, if there is something easy to extract.

Anyway, maybe this is good for now, what we need some locks.
Maybe check if the *.dlls was already loaded or is being loaded.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer as reported here above, @shargon @erikzhang

cschuchardt88
cschuchardt88 previously approved these changes Dec 4, 2025
vncoelho
vncoelho previously approved these changes Dec 4, 2025
@vncoelho
Copy link
Member

vncoelho commented Dec 4, 2025

neo> FATAL [11:21:36.286] 	System.IO.IOException
Failed to bind to address http://0.0.0.0:30337: address already in use.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__14_1(IHostedService service, CancellationToken token)
   at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Start(IHost host)
   at Neo.Plugins.RpcServer.RpcServer.StartRpcServer()
   at Neo.Plugins.RpcServer.RpcServerPlugin.OnSystemLoaded(NeoSystem system)
   at Neo.NeoSystem..ctor(ProtocolSettings settings, IStoreProvider storageProvider, String storagePath) in /opt/neo/src/Neo/NeoSystem.cs:line 153
   at Neo.NeoSystem..ctor(ProtocolSettings settings, String storageProvider, String storagePath) in /opt/neo/src/Neo/NeoSystem.cs:line 128
   at Neo.CLI.MainService.Start(CommandLineOptions options) in /opt/neo-node/src/Neo.CLI/CLI/MainService.cs:line 370
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__124_1(Object state)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()

Microsoft.AspNetCore.Connections.AddressInUseException
Address already in use
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken)

System.Net.Sockets.SocketException
Address already in use
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()

Unhandled exception. System.IO.IOException: Failed to bind to address http://0.0.0.0:30337: address already in use.
 ---> Microsoft.AspNetCore.Connections.AddressInUseException: Address already in use
 ---> System.Net.Sockets.SocketException (98): Address already in use
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__14_1(IHostedService service, CancellationToken token)
   at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Start(IHost host)
   at Neo.Plugins.RpcServer.RpcServer.StartRpcServer()
   at Neo.Plugins.RpcServer.RpcServerPlugin.OnSystemLoaded(NeoSystem system)
   at Neo.NeoSystem..ctor(ProtocolSettings settings, IStoreProvider storageProvider, String storagePath) in /opt/neo/src/Neo/NeoSystem.cs:line 153
   at Neo.NeoSystem..ctor(ProtocolSettings settings, String storageProvider, String storagePath) in /opt/neo/src/Neo/NeoSystem.cs:line 128
   at Neo.CLI.MainService.Start(CommandLineOptions options) in /opt/neo-node/src/Neo.CLI/CLI/MainService.cs:line 370
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__124_1(Object state)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()
/opt/start_node.sh: line 2:   141 Aborted                 (core dumped) ( cd /opt/node/Neo.CLI/; dotnet neo-cli.dll )
root@3acab277a648:/opt/node/Neo.CLI/Plugins/SignClient# root@neocompiler:~/neocompiler-server/neocompiler.io# 

This is the error of a duplicated RpcServer.dll in different Plugins folder, such as those that use it as dependencies.

@vncoelho
Copy link
Member

vncoelho commented Dec 4, 2025

@ajara87 , for one case it helped, but for the duplicated RpcServer dll in different Plugins folder it still do not give much information, just that we have duplicated service on that port.

@vncoelho vncoelho self-requested a review December 4, 2025 11:24
@vncoelho vncoelho dismissed their stale review December 4, 2025 11:24

Maybe verify for if improve log for duplicated RpcServer dlls

@vncoelho
Copy link
Member

vncoelho commented Dec 4, 2025

Maybe , in the specific case of the RpcServer duplicated, we need something to avoid loading a duplicated * dlls, a flag that says it is "loading"/"loaded"

vncoelho
vncoelho previously approved these changes Dec 4, 2025
@ajara87 ajara87 dismissed stale reviews from vncoelho and cschuchardt88 via eb04497 December 4, 2025 15:23
@vncoelho
Copy link
Member

vncoelho commented Dec 5, 2025

What is the problem with the location as @ajara87 initially designed.

Now it is bad and still missing important information on location

ERROR [17:13:05.523] 	Failed to load plugin assembly Grpc.Net.Client: System.TypeLoadException: Could not load type 'Grpc.Core.ConnectivityState' from assembly 'Grpc.Net.Common, Version=2.0.0.0,  Culture=neutral,  PublicKeyToken=d754f35622...in.cs:line  177
NEO-CLI v3.9.0  -  NEO v3.9.0  -  NEO-VM v3.9.0

neo> Unhandled exception. System.TypeInitializationException: The type initializer for 'Neo.NeoSystem' threw an exception.
 ---> System.TypeLoadException: Could not load type 'Grpc.Core.ConnectivityState' from assembly 'Grpc.Net.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad'.
   at System.Reflection.RuntimeAssembly.GetExportedTypes()
   at Neo.Plugins.Plugin.LoadPlugin(Assembly assembly) in /opt/neo/src/Neo/Plugins/Plugin.cs:line 177
   at Neo.Plugins.Plugin.LoadPlugins() in /opt/neo/src/Neo/Plugins/Plugin.cs:line 223
   at Neo.NeoSystem..cctor() in /opt/neo/src/Neo/NeoSystem.cs:line 112
   --- End of inner exception stack trace ---
   at Neo.NeoSystem.CurrentDomain_UnhandledException(Object sender, UnhandledExceptionEventArgs e) in /opt/neo/src/Neo/NeoSystem.cs:line 185
   at System.AppContext.OnUnhandledException(Object e)
/opt/start_node.sh: line 2:   120 Aborted                 (core dumped) ( cd /opt/node/Neo.CLI/; dotnet neo-cli.dll )

Copy link
Member

@vncoelho vncoelho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is it does not improve much readability, the first version was better.
What are the problems in printing location?

@ajara87 ajara87 requested review from erikzhang and shargon December 6, 2025 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants