Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash: Realm.SyncSession is only valid for synchronized Realms #3562

Closed
softlion opened this issue Mar 22, 2024 · 7 comments
Closed

Crash: Realm.SyncSession is only valid for synchronized Realms #3562

softlion opened this issue Mar 22, 2024 · 7 comments

Comments

@softlion
Copy link

softlion commented Mar 22, 2024

What happened?

realm 11.7.0

Real crashed while reading a table.

Db = Realm.GetInstance();
var x = Db.All<DbWallet>().ToList()

Exception:

System.NotSupportedException: Realm.SyncSession is only valid for synchronized Realms (i.e. ones that are opened with FlexibleSyncConfiguration or PartitionSyncConfiguration). The unsupported member type is located on type 'Realms.Sync.Session'. Path: $.Realm.SyncSession.
 ---> System.NotSupportedException: Realm.SyncSession is only valid for synchronized Realms (i.e. ones that are opened with FlexibleSyncConfiguration or PartitionSyncConfiguration).
   at Realms.Realm.get_SyncSession() in D:\a\realm-dotnet\realm-dotnet\Realm\Realm\Realm.cs:line 247

Repro steps

var wallet = Db.Find<DbWallet>(walletId);

await Db.WriteAsync(() =>  {   wallet.Alias = "some new value";   });

var allWallets = Db.All<DbWallet>().ToList();

Version

8.0

What Atlas Services are you using?

Local Database only

What type of application is this?

Other

Client OS and version

Maui. Android emulator API 33 (pixel 5) on windows 11.

Code snippets

public partial class DbWallet : IRealmObject
{
    [PrimaryKey]
    public string WalletId { get; set; }
    public string? Alias { get; set; }
}

Stacktrace of the exception/crash you're getting

System.NotSupportedException: Realm.SyncSession is only valid for synchronized Realms (i.e. ones that are opened with FlexibleSyncConfiguration or PartitionSyncConfiguration). The unsupported member type is located on type 'Realms.Sync.Session'. Path: $.Realm.SyncSession.
 ---> System.NotSupportedException: Realm.SyncSession is only valid for synchronized Realms (i.e. ones that are opened with FlexibleSyncConfiguration or PartitionSyncConfiguration).
   at Realms.Realm.get_SyncSession() in D:\a\realm-dotnet\realm-dotnet\Realm\Realm\Realm.cs:line 247

Relevant log output

No response

Copy link

sync-by-unito bot commented Mar 22, 2024

➤ PM Bot commented:

Jira ticket: RNET-1128

@papafe papafe self-assigned this Mar 22, 2024
@papafe
Copy link
Contributor

papafe commented Mar 22, 2024

Hi @softlion, thanks for your report.
The exception that you're seeing should be raised when trying to get a SyncSession on a local realm. From the code snippets that you posted it seems you're indeed creating a local realm, but I don't see you accessing SyncSession anywhere, so I'm not sure how it could happen. I also took a look at our source code and we access SyncSession only with a synchronized realm (when opening the realm with FlexibleSyncConfiguration or PartitionSyncConfiguration), so it shouldn't be possible.

Is that the whole stack trace you're getting? From that I can't see where the SyncSession is accessed.
Would it be possible to for you to create a repro case and send it to us? This would be really helpful

@papafe papafe added the Waiting-For-Reporter Waiting for more information from the reporter before we can proceed label Mar 22, 2024
@softlion
Copy link
Author

softlion commented Mar 22, 2024

That triggers the issue.

The key that triggers it is the json serializer (using System.Text.Json;)

    [Fact]
    public async Task TriggerRealmBug()
    {
        using var db = Realm.GetInstance(new InMemoryConfiguration("unittests"));

        var walletId = "someId";
        var wallet = new DbWallet { WalletId = walletId };
        await db.WriteAsync(() => { db.Add(wallet); });
        
        wallet = db.Find<DbWallet>(walletId);
        await db.WriteAsync(() =>  { wallet.Alias = "some new value"; });
        
        var dbWallets = db.All<DbWallet>().ToList();
        Assert.Single(dbWallets);

        //Crash here
        var jsonWallets = JsonSerializer.Serialize(db.All<DbWallet>().ToList());
    }
 public partial class DbWallet : IRealmObject
{
    [PrimaryKey]
    public string WalletId { get; set; }
    public string? Alias { get; set; }
}

I worked around using a new domain object and mapperly.
But that used to work, as I am only republishing an existing app with the latest nugets.

@github-actions github-actions bot added Needs-Attention Reporter has responded. Review comment. and removed Waiting-For-Reporter Waiting for more information from the reporter before we can proceed labels Mar 22, 2024
@papafe
Copy link
Contributor

papafe commented Mar 22, 2024

Ok, this makes sense. It seems that System.Text.Json is ignoring the IgnoreDataMember attribute we put on the source generated class properties so that they're ignored by the serialization. During the serialization System.Text.Json is trying to access DbWallet.Realm.SyncSession and so the exception is raised.

It seems we need to add the JsonIgnore attribute to be compatible with System.Text.Json. In the meanwhile, you can add special support for IgnoreDataMember as explained here:

//NOTE: This is copied from the link above
var options = new JsonSerializerOptions
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers = { DetectIgnoreDataMemberAttribute }
    }
};

JsonSerializer.Serialize(new MyPoco(), options); // {"Value":3}

static void DetectIgnoreDataMemberAttribute(JsonTypeInfo typeInfo)
{
    if (typeInfo.Kind != JsonTypeInfoKind.Object)
        return;

    foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
    {
        if (propertyInfo.AttributeProvider is ICustomAttributeProvider provider &&
            provider.IsDefined(typeof(IgnoreDataMemberAttribute), inherit: true))
        {
            // Disable both serialization and deserialization 
            // by unsetting getter and setter delegates
            propertyInfo.Get = null;
            propertyInfo.Set = null;
        }
    }
}

To be honest I am surprised this was working before. You said you updated your nuget packages and this stopped working. What nuget packages did you exactly update?

@nirinchev
Copy link
Member

nirinchev commented Mar 22, 2024

Edit: Looks like @papafe beat me to this 😅 This is just repeating what Ferdinando is saying, but with less detail.

Looks like the json serializer is trying to serialize the Realm property on DBWallet, even though it's annotated with IgnoreDataMember. I don't think we can polyfill JsonIgnoreAttribute, so we'll probably need to apply it if possible based on the compilation target.

@softlion
Copy link
Author

softlion commented Mar 22, 2024

Ok, this makes sense. It seems that System.Text.Json is ignoring the IgnoreDataMember attribute we put on the source generated class properties so that they're ignored by the serialization. During the serialization System.Text.Json is trying to access DbWallet.Realm.SyncSession and so the exception is raised.

It seems we need to add the JsonIgnore attribute to be compatible with System.Text.Json. In the meanwhile, you can add special support for IgnoreDataMember as explained here:

//NOTE: This is copied from the link above
var options = new JsonSerializerOptions
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers = { DetectIgnoreDataMemberAttribute }
    }
};

JsonSerializer.Serialize(new MyPoco(), options); // {"Value":3}

static void DetectIgnoreDataMemberAttribute(JsonTypeInfo typeInfo)
{
    if (typeInfo.Kind != JsonTypeInfoKind.Object)
        return;

    foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
    {
        if (propertyInfo.AttributeProvider is ICustomAttributeProvider provider &&
            provider.IsDefined(typeof(IgnoreDataMemberAttribute), inherit: true))
        {
            // Disable both serialization and deserialization 
            // by unsetting getter and setter delegates
            propertyInfo.Get = null;
            propertyInfo.Set = null;
        }
    }
}

To be honest I am surprised this was working before. You said you updated your nuget packages and this stopped working. What nuget packages did you exactly update?

maui, realm, json, and some others.
It may not have worked previously though, it may only not have reported the crash.
The tools have improved and now report the crash.

Anyway now we found the issue.

@sync-by-unito sync-by-unito bot removed the Needs-Attention Reporter has responded. Review comment. label Mar 22, 2024
@papafe
Copy link
Contributor

papafe commented Jun 25, 2024

This has been solved with #3451, so I am closing it

@papafe papafe closed this as completed Jun 25, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants