Skip to content

ConsulDiscoveryClient throws ArgumentNullException for services with null Metadata #1629

@mrshadowc

Description

@mrshadowc

Bug Summary

The ConsulDiscoveryClient in Steeltoe V4 crashes with a System.ArgumentNullException when attempting to resolve a service instance that was registered in Consul without any Metadata (Meta). The ConsulServiceInstance constructor attempts to convert the service's metadata into a ReadOnlyDictionary without checking if the source dictionary is null.


GitHub Issue Template

You can copy and paste the content below directly into a new GitHub Issue.

Title:
[Bug] ArgumentNullException in ConsulServiceInstance when Service Metadata is null

Description:
I am using Steeltoe.Discovery.Consul (V4) to discover services registered in Consul. When the .NET client attempts to resolve a service instance (e.g., a Python FastAPI service) that was registered without any Metadata/Tags, the application crashes with a System.ArgumentNullException.

It appears that the ConsulServiceInstance constructor does not handle null values for Service.Meta before attempting to create a ReadOnlyDictionary.

Steps to Reproduce:

  1. Register a service in Consul (e.g., using python-consul or raw HTTP API) without providing any Meta or Tags data.
    // Example Consul Service definition causing the issue
    {
      "Name": "fastapi-hello",
      "Port": 8000,
      "Meta": null 
    }
  2. Configure a .NET 6/8 application with AddServiceDiscovery() using Steeltoe V4.
  3. Attempt to fetch instances using IDiscoveryClient.GetInstancesAsync() or make a request using the configured HttpClient.

Expected Behavior:
The client should handle null metadata gracefully (e.g., treat it as an empty dictionary) and successfully return the service instance.

Actual Behavior:
The application throws a System.ArgumentNullException originating from the ConsulServiceInstance constructor.

Stack Trace:

System.ArgumentNullException: Value cannot be null. (Parameter 'dictionary')
   at System.ArgumentNullException.Throw(String paramName)
   at System.Collections.ObjectModel.ReadOnlyDictionary`2..ctor(IDictionary`2 dictionary)
   at System.Collections.Generic.CollectionExtensions.AsReadOnly[TKey,TValue](IDictionary`2 dictionary)
   at Steeltoe.Discovery.Consul.ConsulServiceInstance..ctor(ServiceEntry serviceEntry) in /_/src/Discovery/src/Consul/ConsulServiceInstance.cs:line 48
   at Steeltoe.Discovery.Consul.ConsulDiscoveryClient.<>c.<AddInstancesToListAsync>b__15_0(ServiceEntry entry)
   at System.Linq.Enumerable.ArraySelectIterator`2.MoveNext()
   at Steeltoe.Discovery.Consul.ConsulDiscoveryClient.AddInstancesToListAsync(...)
   at Steeltoe.Discovery.Consul.ConsulDiscoveryClient.GetInstancesAsync(...)
   at Steeltoe.Discovery.HttpClients.LoadBalancers.ServiceInstancesResolver.ResolveInstancesAsync(...)

Environment:

  • Steeltoe Version: 4.0.x (Discovery.Consul)
  • Target Framework: .NET 6 / .NET 8
  • Consul Version: (Any)

Possible Fix / Workaround:
Currently, I have to ensure that non-NET services register with at least one dummy metadata entry (e.g., meta={"fix": "true"}) to prevent the client from crashing. The constructor in ConsulServiceInstance.cs should check for null before calling AsReadOnly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions