kordlib / kord

Idiomatic Kotlin Wrapper for The Discord API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nullability issue with TextChannel.createMessage and EmbedBuilder.Author

Loatchi opened this issue · comments

When working on a bot of mine I to be able to create message from a text channel 's id.

However I found out that when creating and embed with an author field you must mention both the name and the url otherwise the deserializer will stop on a null value.

val myGuildSnowflake: Snowflake
val myTextChannelSnowflake: Snowflake

(kord.getGuildOrThrow(myGuildSnowflake)
    .getChannel(myTextChannelSnowflake) as TextChannel)
    .createMessage {
    embed {
        description = "foo"
        author {
            name = "bar"
        }
    }
}

would cause:

Exception in thread "main" kotlinx.serialization.SerializationException: descriptor for kotlin.String was not nullable but null mark was encountered
	at dev.kord.common.entity.optional.Optional$OptionalSerializer.deserialize(Optional.kt:164)
	at dev.kord.common.entity.optional.Optional$OptionalSerializer.deserialize(Optional.kt:155)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:70)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableElement(StreamingJsonDecoder.kt:165)
	at dev.kord.common.entity.DiscordEmbed$Author$$serializer.deserialize(DiscordMessage.kt:670)
	at dev.kord.common.entity.DiscordEmbed$Author$$serializer.deserialize(DiscordMessage.kt:670)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:70)
	at dev.kord.common.entity.optional.Optional$OptionalSerializer.deserialize(Optional.kt:177)
	at dev.kord.common.entity.optional.Optional$OptionalSerializer.deserialize(Optional.kt:155)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:70)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableElement(StreamingJsonDecoder.kt:165)
	at dev.kord.common.entity.DiscordEmbed$$serializer.deserialize(DiscordMessage.kt:569)
	at dev.kord.common.entity.DiscordEmbed$$serializer.deserialize(DiscordMessage.kt:569)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:70)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableElement(StreamingJsonDecoder.kt:165)
	at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:533)
	at kotlinx.serialization.internal.CollectionLikeSerializer.readElement(CollectionSerializers.kt:80)
	at kotlinx.serialization.internal.AbstractCollectionSerializer.readElement$default(CollectionSerializers.kt:51)
	at kotlinx.serialization.internal.AbstractCollectionSerializer.merge(CollectionSerializers.kt:36)
	at kotlinx.serialization.internal.AbstractCollectionSerializer.deserialize(CollectionSerializers.kt:43)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:70)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableValue(AbstractDecoder.kt:43)
	at kotlinx.serialization.encoding.AbstractDecoder.decodeSerializableElement(AbstractDecoder.kt:70)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableElement(StreamingJsonDecoder.kt:165)
	at dev.kord.common.entity.DiscordMessage$$serializer.deserialize(DiscordMessage.kt:164)
	at dev.kord.common.entity.DiscordMessage$$serializer.deserialize(DiscordMessage.kt:164)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:70)
	at kotlinx.serialization.json.Json.decodeFromString(Json.kt:107)
	at dev.kord.rest.route.ValueJsonMapper.deserialize(Route.kt:24)
	at dev.kord.rest.request.KtorRequestHandler.handle(KtorRequestHandler.kt:68)
	at dev.kord.rest.request.KtorRequestHandler$handle$1.invokeSuspend(KtorRequestHandler.kt)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:177)
	at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
	at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
	at kotlinx.coroutines.ResumeOnCompletion.invoke(JobSupport.kt:1390)
	at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1494)
	at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:324)
	at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:241)
	at kotlinx.coroutines.JobSupport.continueCompleting(JobSupport.kt:938)
	at kotlinx.coroutines.JobSupport.access$continueCompleting(JobSupport.kt:25)
	at kotlinx.coroutines.JobSupport$ChildCompletion.invoke(JobSupport.kt:1158)
	at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1494)
	at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:324)
	at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:241)
	at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:909)
	at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:866)
	at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:831)
	at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:100)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

However simply adding:

author {
    name = "bar"
    url = "https://github.com/kordlib/kord" // any link here
}

would work.

It is similar to this already closed issue.

However it's for the url field in author's embed.
So it should be fixable by simply allowing null value here.

This looks like a documentation error on Discord side, since all fields are not nullable here, could you turn on TRACE LOGGING and share the exact JSON coming back?

There you go, this is the Json that came back when sending a message this way.

{
  "id": "1121768099201421412",
  "type": 0,
  "content": "",
  "channel_id": "xxxx",
  "author": {
      ...
  },
  "attachments": [],
  "embeds": [
    {
      "type": "rich",
      "description": "foo",
      "author": {
        "name": "bar",
        "url": null
      }
    }
  ],
  "mentions": [],
  "mention_roles": [],
  "pinned": false,
  "mention_everyone": false,
  "tts": false,
  "timestamp": "2023-06-23T11:45:56.293000+00:00",
  "edited_timestamp": null,
  "flags": 0,
  "components": [],
  "referenced_message": null
}

I've truncated author and channel but they are looking fine and indeed the url part is null instead of missing.

i think we should just change the type of DiscordEmbed.Author.url to Optional<String?>, should work then

@Loatchi can you try if the fix in #839 is working using fix-null-embed-author-url-SNAPSHOT?

might want to send this to the @discord repo?

Ok sorry for the long response time I had to fight against gradle pulling the 0.9.0 dep.

Running the same command as I started with does indeed work @lukellmann.

I'll open a ticket on the discord api docs.

0.10.0-SNAPSHOT should now also contain the fix