Skip to content

A JsonSerializationException is thrown when an Audit Log entry is logged with a null user_id #2243

@FloatingMilkshake

Description

@FloatingMilkshake

Summary

When an Audit Log entry is logged with a null user_id, a JsonSerializationException is thrown.

I think these Audit Log entries can be reliably caused by setting a global Display Name that violates the Block Words in Member Profile Names AutoMod rule. user_id being null is obviously not a D#+ issue, but the exception could probably be avoided at least!

Here is an example Audit Log entry:

{
    "id": "1338586191775142058",
    "action_type": 146,
    "user_id": null,
    "target_id": "795484125184131073",
    "options": {
        "auto_moderation_rule_name": "Block Words in Member Profile Names",
        "auto_moderation_rule_trigger_type": "6"
    },
    "reason": "Profile contained keyword that violated Block Words in Member Profile Names rule"
},

What version of the library are you using?

v5.0.0-nightly (make sure you are using the latest nightly!)

What .NET version are you using? Make sure to use the latest patch release for your major version.

.NET 9.0

Operating System

No response

Reproduction Steps

  1. Set up the "Block Words in Member Profile Names" AutoMod rule and add a word
  2. Set your global Display Name so that it contains the blocked word
  3. Go look at your console

These null Audit Log entries are also noticeably different from other ones when viewing the Audit Log on Discord:

Image

(flagged vs quarantined doesn't make a difference, "Unknown User"/null is logged for both—the bottom entry here is a nickname update just to show the difference!)

Trace Logs

[2025-02-12 16:15:08 -05:00] [Verbose] Payload for the last inbound gateway event: "{\"t\":\"GUILD_MEMBER_UPDATE\",\"s\":18,\"op\":0,\"d\":{\"user\":{\"username\":\"testingmilkshake2\",\"public_flags\":0,\"primary_guild\":null,\"id\":\"1039361869229596742\",\"global_name\":\"testingmilkshake 2\",\"discriminator\":\"0\",\"clan\":null,\"avatar_decoration_data\":null,\"avatar\":\"2972f294d83f9b1ccf68dec652f4fd03\"},\"unusual_dm_activity_until\":null,\"roles\":[],\"premium_since\":null,\"pending\":false,\"nick\":null,\"joined_at\":\"2025-02-12T21:05:42.984000+00:00\",\"guild_id\":\"885928970137260093\",\"flags\":128,\"communication_disabled_until\":null,\"banner\":null,\"avatar\":null}}"
[2025-02-12 16:15:08 -05:00] [Verbose] Length for the last inbound gateway event: 295
[2025-02-12 16:15:08 -05:00] [Verbose] Payload for the last inbound gateway event: "{\"t\":\"MESSAGE_CREATE\",\"s\":19,\"op\":0,\"d\":{\"type\":24,\"tts\":false,\"timestamp\":\"2025-02-12T21:15:08.285000+00:00\",\"pinned\":false,\"mentions\":[],\"mention_roles\":[],\"mention_everyone\":false,\"member\":{\"roles\":[],\"premium_since\":null,\"pending\":false,\"nick\":null,\"mute\":false,\"joined_at\":\"2025-02-12T21:05:42.984000+00:00\",\"flags\":128,\"deaf\":false,\"communication_disabled_until\":null,\"banner\":null,\"avatar\":null},\"id\":\"1339344062397808750\",\"flags\":0,\"embeds\":[{\"type\":\"auto_moderation_message\",\"fields\":[{\"value\":\"Block Words in Member Profile Names\",\"name\":\"rule_name\",\"inline\":false},{\"value\":\"866e5f69c7734ea1b927048b92807848\",\"name\":\"decision_id\",\"inline\":false},{\"value\":\"testingmilkshake\",\"name\":\"keyword\",\"inline\":false},{\"value\":\"testingmilkshake\",\"name\":\"keyword_matched_content\",\"inline\":false},{\"value\":\"flagged\",\"name\":\"decision_outcome\",\"inline\":false},{\"value\":\"display_name\",\"name\":\"quarantine_user\",\"inline\":false},{\"value\":\"username_update\",\"name\":\"quarantine_event\",\"inline\":false},{\"value\":\"quarantine_user\",\"name\":\"quarantine_user_action\",\"inline\":false}],\"description\":\"testingmilkshake 2\",\"content_scan_version\":0}],\"edited_timestamp\":null,\"content\":\"\",\"components\":[],\"channel_type\":0,\"channel_id\":\"885928970481205285\",\"author\":{\"username\":\"testingmilkshake2\",\"public_flags\":0,\"primary_guild\":null,\"id\":\"1039361869229596742\",\"global_name\":\"testingmilkshake 2\",\"discriminator\":\"0\",\"clan\":null,\"avatar_decoration_data\":null,\"avatar\":\"2972f294d83f9b1ccf68dec652f4fd03\"},\"attachments\":[],\"guild_id\":\"885928970137260093\"}}"
[2025-02-12 16:15:08 -05:00] [Verbose] Length for the last inbound gateway event: 129
[2025-02-12 16:15:08 -05:00] [Verbose] Payload for the last inbound gateway event: "{\"t\":\"GUILD_AUDIT_LOG_ENTRY_CREATE\",\"s\":20,\"op\":0,\"d\":{\"user_id\":null,\"target_id\":\"1039361869229596742\",\"reason\":\"Profile contained keyword that violated Block Words in Member Profile Names rule\",\"options\":{\"auto_moderation_rule_trigger_type\":\"6\",\"auto_moderation_rule_name\":\"Block Words in Member Profile Names\"},\"id\":\"1339344062397808751\",\"action_type\":146,\"guild_id\":\"885928970137260093\"}}"
[2025-02-12 16:15:08 -05:00] [Verbose] Length for the last inbound gateway event: 104
[2025-02-12 16:15:08 -05:00] [Verbose] Payload for the last inbound gateway event: "{\"t\":\"AUTO_MODERATION_ACTION_EXECUTION\",\"s\":21,\"op\":0,\"d\":{\"user_id\":\"1039361869229596742\",\"rule_trigger_type\":6,\"rule_id\":\"1301982521294192690\",\"matched_keyword\":\"testingmilkshake\",\"matched_content\":\"testingmilkshake\",\"content\":\"\",\"action\":{\"type\":4,\"metadata\":{}},\"guild_id\":\"885928970137260093\"}}"
[2025-02-12 16:15:08 -05:00] [Verbose] Length for the last inbound gateway event: 32
[2025-02-12 16:15:08 -05:00] [Verbose] Payload for the last inbound gateway event: "{\"t\":\"GUILD_AUDIT_LOG_ENTRY_CREATE\",\"s\":22,\"op\":0,\"d\":{\"user_id\":null,\"target_id\":\"1039361869229596742\",\"reason\":\"Profile contained keyword that violated Block Words in Member Profile Names rule\",\"options\":{\"auto_moderation_rule_trigger_type\":\"6\",\"auto_moderation_rule_name\":\"Block Words in Member Profile Names\"},\"id\":\"1339344062851055768\",\"action_type\":144,\"guild_id\":\"885928970137260093\"}}"
[2025-02-12 16:15:08 -05:00] [Verbose] Length for the last inbound gateway event: 41
[2025-02-12 16:15:08 -05:00] [Verbose] Payload for the last inbound gateway event: "{\"t\":\"AUTO_MODERATION_ACTION_EXECUTION\",\"s\":23,\"op\":0,\"d\":{\"user_id\":\"1039361869229596742\",\"rule_trigger_type\":6,\"rule_id\":\"1301982521294192690\",\"matched_keyword\":\"testingmilkshake\",\"matched_content\":\"testingmilkshake\",\"content\":\"\",\"alert_system_message_id\":\"1339344062397808750\",\"action\":{\"type\":2,\"metadata\":{\"channel_id\":\"885928970481205285\"}},\"guild_id\":\"885928970137260093\"}}"
[2025-02-12 16:15:08 -05:00] [Error] Dispatch threw an exception: 
Newtonsoft.Json.JsonSerializationException: Error converting value {null} to type 'System.UInt64'. Path 'user_id'.
 ---> System.InvalidCastException: Null object cannot be converted to a value type.
[...]

Exceptions or other error messages

[Error] Dispatch threw an exception: 
Newtonsoft.Json.JsonSerializationException: Error converting value {null} to type 'System.UInt64'. Path 'user_id'.
 ---> System.InvalidCastException: Null object cannot be converted to a value type.
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Newtonsoft.Json.Linq.JToken.ToObject[T](JsonSerializer jsonSerializer)
   at DSharpPlus.Net.Serialization.DiscordJson.ToDiscordObject[T](JToken token)
   at DSharpPlus.DiscordClient.HandleDispatchAsync(GatewayPayload payload)
   at DSharpPlus.DiscordClient.ReceiveGatewayEventsAsync()

Anything else you'd like to share

No response

Metadata

Metadata

Assignees

Labels

audit-logIssues about missing auditlog types or missing change keycore

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions