nats-io / nats.net

Full Async C# / .NET client for NATS
https://nats-io.github.io/nats.net
Apache License 2.0
262 stars 53 forks source link

NatsKVContext.GetStoreAsync fails to get store created by NATS CLI #393

Closed ronnieoverby closed 8 months ago

ronnieoverby commented 9 months ago

Observed behavior

When I call NatsKVContext.GetStoreAsync(…) for a bucket/store that was created using the NATS CLI, I get a System.Text.Json.JsonException:

Message: JSON deserialization for type 'NATS.Client.JetStream.Models.Placement' was missing required properties, including the following: cluster

StackTrace:
   at System.Text.Json.ThrowHelper.ThrowJsonException_JsonRequiredPropertyMissing(JsonTypeInfo parent, BitArray requiredPropertiesSet)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Deserialize(Utf8JsonReader& reader, ReadStack& state)
   at System.Text.Json.JsonSerializer.Read[TValue](Utf8JsonReader& reader, JsonTypeInfo`1 jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](Utf8JsonReader& reader, JsonTypeInfo`1 jsonTypeInfo)
   at NATS.Client.Core.NatsJsonContextSerializer`1.Deserialize(ReadOnlySequence`1& buffer)
   at NATS.Client.Core.NatsJsonContextSerializer`1.NATS.Client.Core.INatsDeserialize<T>.Deserialize(ReadOnlySequence`1& buffer)
   at NATS.Client.JetStream.Internal.NatsJSErrorAwareJsonSerializer`1.Deserialize(ReadOnlySequence`1& buffer)
   at NATS.Client.JetStream.Internal.NatsJSErrorAwareJsonSerializer`1.NATS.Client.Core.INatsDeserialize<T>.Deserialize(ReadOnlySequence`1& buffer)
   at NATS.Client.Core.NatsMsg`1.Build(String subject, String replyTo, Nullable`1& headersBuffer, ReadOnlySequence`1& payloadBuffer, INatsConnection connection, NatsHeaderParser headerParser, INatsDeserialize`1 serializer)
   at NATS.Client.Core.NatsSub`1.ReceiveInternalAsync(String subject, String replyTo, Nullable`1 headersBuffer, ReadOnlySequence`1 payloadBuffer)
   at NATS.Client.Core.NatsSubBase.ReceiveAsync(String subject, String replyTo, Nullable`1 headersBuffer, ReadOnlySequence`1 payloadBuffer)
   at NATS.Client.Core.NatsSubBase.DisposeAsync()
   at NATS.Client.JetStream.NatsJSContext.JSRequestAsync[TRequest,TResponse](String subject, TRequest request, CancellationToken cancellationToken)
   at NATS.Client.JetStream.NatsJSContext.JSRequestResponseAsync[TRequest,TResponse](String subject, TRequest request, CancellationToken cancellationToken)
   at NATS.Client.JetStream.NatsJSContext.GetStreamAsync(String stream, StreamInfoRequest request, CancellationToken cancellationToken)
   at NATS.Client.KeyValueStore.NatsKVContext.GetStoreAsync(String bucket, CancellationToken cancellationToken)
   at UserQuery.Main(), line 24

Expected behavior

I expect the KV store to be returned without error. This is what happens when interacting with the KV store from the NATS CLI or the legacy .NET Client (nuget package NATS.Client 1.1.2).

The call succeeds when getting stores created with the same client library or with the older legacy library.

Server and client version

Server Version: 2.10.7 CLI Version: both 0.1.1 and 0.0.35 Nuget Packages : 2.1.0

Host environment

Everything running on Windows 11 version 22H2 x64

Steps to reproduce

From CLI

> .\nats-server.exe -js

> nats kv add clibucket

C# Program with NATS.Net 2.1.0 package installed

var nats = new NatsConnection(NatsOpts.Default with
{
    //SerializerRegistry = NatsJsonSerializerRegistry.Default, // error with or without this
});

await nats.ConnectAsync();

var js = new NatsJSContext(nats);
var kv = new NatsKVContext(js);
await kv.CreateStoreAsync("goodBucket");

var goodBucket = await kv.GetStoreAsync("goodBucket");
Console.WriteLine(goodBucket.Bucket);

var cliBucket = await kv.GetStoreAsync("clibucket"); // throws JsonException
mtmk commented 9 months ago

thanks for the report 💯 Fix PR is in motion. I will prepare a patch release soon.