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

why editReply return discord4j.rest.http.client.ClientException *** 404 Not Found ? #1109

Closed
jqnote opened this issue Dec 23, 2022 · 1 comment
Labels
question Question about a feature or decision in this project

Comments

@jqnote
Copy link

jqnote commented Dec 23, 2022

pom.xml

<dependency>
    <groupId>com.discord4j</groupId>
    <artifactId>discord4j-core</artifactId>
    <version>3.2.3</version>
</dependency>

exception

discord4j.rest.http.client.ClientException: POST /interactions/10558398405806*****/aW50ZX*****lZa05mWg/callback returned 404 Not Found with response {code=10062, message=Unknown interaction}
	at discord4j.rest.http.client.ClientResponse.clientException(ClientResponse.java:171)
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ Request to POST /interactions/10558398405806*****/aW50****/callback [RequestStream]
	*__checkpoint ⇢ Request to POST /interactions/10558398405806*****/aW50****/callback [DefaultRouter]
Original Stack Trace:
		at discord4j.rest.http.client.ClientResponse.clientException(ClientResponse.java:171)
		at discord4j.rest.http.client.ClientResponse.lambda$createException$13(ClientResponse.java:149)
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
		at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
		at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
		at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:126)
		at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
		at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
		at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854)
		at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onNext(FluxMap.java:224)
		at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onNext(FluxDoFinally.java:113)
		at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:191)
		at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
		at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:129)
		at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260)
		at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
		at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:400)
		at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:419)
		at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:473)
		at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:702)
		at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
		at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:336)
		at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:308)
		at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1373)
		at io.netty.handler.ssl.SslHandler.decodeNonJdkCompatible(SslHandler.java:1247)
		at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1287)
		at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:519)
		at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:458)
		at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:280)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
		at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800)
		at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:499)
		at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:397)
		at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
		at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
		at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
		at java.lang.Thread.run(Thread.java:748)

confusion

only the case b threws out the ClientException, but case a and case c work good. why?

code

image

@quanticc
Copy link
Member

This is likely a case of methodThatTakesALongTime running before deferReply is sent, taking more than the time required by Discord to reply (3 seconds). If you reply after that, the interaction is deleted and you get 404.

Why does it run before deferReply:

Before the Mono pipeline you return is subscribed to, Java calls the methods in lines 157-160 that assemble the sequence. By that point it's only an async description of what should run once subscribed. In Reactor this is called "assembly time".

However if significant work is done during assembly time, that can take valuable time towards your 3 second limit.

The fix would be to implement methodThatTakesALongTime inside a lambda so Java doesn't actually run the method until it's subscribed, Reactor calls that "subscription time".

public Mono<Void> methodThatTakesALongTime() {
	return Mono.fromCallable(() -> {
		// your previous code
	});
}

or wrap the outer call with defer

.then(Mono.defer(() -> methodThatTakesALongTime(...)))

Depending on how is the method implemented

Why are A and C working?

A works because all methods in the chain are compliant with reactor where no significant work should happen before you subscribe. methodThatTakesALongTime can be adapted to respect this too.

C works because you explicitly subscribe so the HTTP defer call is done immediately. However this removes proper error handling as you won't be able to handle errors if the HTTP call fails.

Hope this helps and sorry for the delayed response!

@quanticc quanticc added the question Question about a feature or decision in this project label Jan 29, 2023
@quanticc quanticc pinned this issue Feb 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Question about a feature or decision in this project
Projects
None yet
Development

No branches or pull requests

2 participants