Describe the bug
When calling ConnectionMultiplexer.GetServers(false), the server topology check that happens assumes that endpoints are using IP addresses. Sometimes endpoints are DNS names, like for AWS's Elasticache service.
When the library tries to force a conversion from a DNS hostname to an IP address, an exception is thrown.
Expected Behavior
Client correctly parses the results of ConnectionMultiplexer.GetServers(false) to System.Net.Endpoint objects, similar to the behavior seen in Redis.StackExchange for the same objects.
Current Behavior
Client throws a system error when failing to parse the DNS hostnames into System.Net.IPEndpoint objects. This is unique to the underlying "GetServers()", as most other parts seem to use System.Net.Endpoint instead.
Exception has occurred: CLR/System.FormatException
An exception of type 'System.FormatException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'An invalid IPEndPoint was specified.'
at System.Net.IPEndPoint.Parse(ReadOnlySpan1 s) at Valkey.Glide.ConnectionMultiplexer.<GetServers>b__11_0(String addr) at System.Linq.Enumerable.IEnumerableSelectIterator2.MoveNext()
at System.Linq.Enumerable.g__EnumerableToArray|324_0[TSource](IEnumerable`1 source)
at Valkey.Glide.ConnectionMultiplexer.GetServers()
at Valkey.Glide.ConnectionMultiplexer.GetEndPoints(Boolean configuredOnly)
at EncompassWebServices.BC_CacheTools.d__5.MoveNext() in /data/Chuck/Inetpub/ECP/EncompassWebServices/DevOps/CacheTools.cs:line 84
Valkey GLIDE C# client version
Other
Valkey GLIDE C# client version (Other)
v1.1.0
.NET version
Other
.NET version (Other)
.NET 10
Engine type and version
Other
Engine type and version (Other)
Valkey 8.2
Engine Environment
ElastiCache Provisioned
Engine Environment (Other)
No response
OS
Amazon Linux
OS (Other)
No response
Logs
⚪ None
Cluster information
- Topology: cluster
- Shards: 2
- Replicas per shard: 0
Reproduction Steps
// Bug: ConnectionMultiplexer.GetEndPoints(false) throws FormatException on cluster with DNS hostnames
// Valkey.Glide v1.1.0, .NET 10.0, Amazon Linux 2023 (ARM64)
// Cluster: AWS ElastiCache Valkey, 2-shard cluster mode enabled
//
// GetEndPoints() internally calls GetServers() which passes discovered DNS hostnames
// through IPEndPoint.Parse(), which fails because they are not IP addresses.
//
// Stack trace:
// System.FormatException: An invalid IPEndPoint was specified.
// at System.Net.IPEndPoint.Parse(ReadOnlySpan`1 s)
// at Valkey.Glide.ConnectionMultiplexer.<GetServers>b__11_0(String addr)
// at System.Linq.Enumerable.IEnumerableSelectIterator`2.MoveNext()
// at System.Linq.Enumerable.<ToArray>g__EnumerableToArray|324_0[TSource](IEnumerable`1 source)
// at Valkey.Glide.ConnectionMultiplexer.GetServers()
// at Valkey.Glide.ConnectionMultiplexer.GetEndPoints(Boolean configuredOnly)
using Valkey.Glide;
// Connect to an ElastiCache Valkey cluster using the clustercfg DNS endpoint
ConfigurationOptions config = new ConfigurationOptions
{
EndPoints = { "my-cluster.clustercfg.usw2.cache.amazonaws.com:6379" },
ConnectTimeout = 10000,
ResponseTimeout = 5000,
Ssl = true,
};
ConnectionMultiplexer multiplexer = ConnectionMultiplexer.Connect(config);
// This works — basic commands route correctly through the multiplexer
IDatabase db = multiplexer.GetDatabase();
await db.StringSetAsync("test-key", "hello");
string value = await db.StringGetAsync("test-key"); // "hello" ✓
// BUG: configuredOnly:false calls throw System.FormatException
// because discovered topology contains DNS hostnames like:
// "my-cluster-0001-001.my-cluster.ozsykg.usw2.cache.amazonaws.com:6379"
// and the library tries to parse them with IPEndPoint.Parse()
try
{
// configuredOnly: false — discovered endpoints
System.Net.EndPoint[] discovered = multiplexer.GetEndPoints(false);
Console.WriteLine($"Discovered endpoints: {discovered.Length}"); // never reached
}
catch (FormatException ex)
{
Console.WriteLine($"GetEndPoints(false) threw: {ex.Message}");
}
try
{
// configuredOnly: true — this works because GetServers() not called
System.Net.EndPoint[] configured = multiplexer.GetEndPoints(true);
Console.WriteLine($"Configured endpoints: {configured.Length}");
}
catch (FormatException ex)
{
Console.WriteLine($"GetEndPoints(true) threw: {ex.Message}"); //never reached, since this path works correctly
}
// Expected: GetEndPoints(false) returns System.Net.Endpoint objects (or similar like DnsEndPoint) for cluster nodes
// Actual: FormatException because IPEndPoint.Parse() cannot handle DNS hostnames
// Workaround: execute CLUSTER NODES directly and parse the output
ValkeyResult result = await db.ExecuteAsync("CLUSTER", "NODES");
string clusterNodes = (string)result;
// Parse "node-id ip:port@cport flags ..." lines to extract master addresses
Possible Solution
Potential fixes for ConnectionMultiplexer.cs:
public IServer[] GetServers()
{
if (_db.IsCluster)
{
Dictionary<string, string> result = _db.Command(Request.Info(Array.Empty<InfoOptions.Section>()).ToMultiNodeValue(), Route.AllNodes).GetAwaiter().GetResult();
return result.Keys.Select((string addr) => new ValkeyServer(_db, ParseEndPoint(addr))).ToArray();
}
// ... standalone case unchanged ...
}
private static EndPoint ParseEndPoint(string addr)
{
// Try IPEndPoint first (handles "1.2.3.4:6379")
if (IPEndPoint.TryParse(addr, out IPEndPoint ipEndPoint))
{
return ipEndPoint;
}
// Fall back to DnsEndPoint for hostnames (handles "my-node.cache.amazonaws.com:6379")
int lastColon = addr.LastIndexOf(':');
if (lastColon > 0 && int.TryParse(addr.AsSpan(lastColon + 1), out int port))
{
return new DnsEndPoint(addr.Substring(0, lastColon), port);
}
throw new FormatException($"Unable to parse endpoint: '{addr}'");
}
And also, a fix to the comparison in GetServer to go along with this change:
public IServer GetServer(EndPoint endpoint)
{
IServer[] servers = GetServers();
string target = endpoint.ToString();
foreach (IServer server in servers)
{
if (server.EndPoint.Equals(endpoint) || server.EndPoint.ToString() == target)
{
return server;
}
}
throw new ArgumentException("The specified endpoint is not defined", nameof(endpoint));
}
Related
⚪ None
Additional Information
If I have time to properly check out and build the repo and test my proposed fix, I'll make a PR for it later.
Describe the bug
When calling ConnectionMultiplexer.GetServers(false), the server topology check that happens assumes that endpoints are using IP addresses. Sometimes endpoints are DNS names, like for AWS's Elasticache service.
When the library tries to force a conversion from a DNS hostname to an IP address, an exception is thrown.
Expected Behavior
Client correctly parses the results of ConnectionMultiplexer.GetServers(false) to System.Net.Endpoint objects, similar to the behavior seen in Redis.StackExchange for the same objects.
Current Behavior
Client throws a system error when failing to parse the DNS hostnames into System.Net.IPEndpoint objects. This is unique to the underlying "GetServers()", as most other parts seem to use System.Net.Endpoint instead.
Exception has occurred: CLR/System.FormatException
An exception of type 'System.FormatException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'An invalid IPEndPoint was specified.'
at System.Net.IPEndPoint.Parse(ReadOnlySpan
1 s) at Valkey.Glide.ConnectionMultiplexer.<GetServers>b__11_0(String addr) at System.Linq.Enumerable.IEnumerableSelectIterator2.MoveNext()at System.Linq.Enumerable.g__EnumerableToArray|324_0[TSource](IEnumerable`1 source)
at Valkey.Glide.ConnectionMultiplexer.GetServers()
at Valkey.Glide.ConnectionMultiplexer.GetEndPoints(Boolean configuredOnly)
at EncompassWebServices.BC_CacheTools.d__5.MoveNext() in /data/Chuck/Inetpub/ECP/EncompassWebServices/DevOps/CacheTools.cs:line 84
Valkey GLIDE C# client version
Other
Valkey GLIDE C# client version (Other)
v1.1.0
.NET version
Other
.NET version (Other)
.NET 10
Engine type and version
Other
Engine type and version (Other)
Valkey 8.2
Engine Environment
ElastiCache Provisioned
Engine Environment (Other)
No response
OS
Amazon Linux
OS (Other)
No response
Logs
⚪ None
Cluster information
Reproduction Steps
Possible Solution
Potential fixes for ConnectionMultiplexer.cs:
And also, a fix to the comparison in GetServer to go along with this change:
Related
⚪ None
Additional Information
If I have time to properly check out and build the repo and test my proposed fix, I'll make a PR for it later.