question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

NullPointerException on stream cancellation

See original GitHub issue

Hi, RSocket maintainers!

We noticed that in some cases we observe NPEs on cancelling streams. E.g.

java.lang.NullPointerException
	at io.rsocket.util.ByteBufPayload.sliceData(ByteBufPayload.java:149)
	at io.rsocket.RSocketRequester$3$1.hookOnNext(RSocketRequester.java:351)
	at io.rsocket.RSocketRequester$3$1.hookOnNext(RSocketRequester.java:333)
	at reactor.core.publisher.BaseSubscriber.onNext(BaseSubscriber.java:160)
	at io.rsocket.internal.RateLimitableRequestPublisher$InnerOperator.onNext(RateLimitableRequestPublisher.java:173)
	at reactor.core.publisher.FluxJust$WeakScalarSubscription.request(FluxJust.java:99)
	at io.rsocket.internal.RateLimitableRequestPublisher.requestN(RateLimitableRequestPublisher.java:124)
	at io.rsocket.internal.RateLimitableRequestPublisher.access$400(RateLimitableRequestPublisher.java:29)
	at io.rsocket.internal.RateLimitableRequestPublisher$InnerOperator.onSubscribe(RateLimitableRequestPublisher.java:167)
	at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:70)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8134)
	at io.rsocket.internal.RateLimitableRequestPublisher.subscribe(RateLimitableRequestPublisher.java:74)
	at io.rsocket.RSocketRequester$3.accept(RSocketRequester.java:332)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:131)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:137)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:137)
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.request(FluxDoFinally.java:150)
	at reactor.core.publisher.FluxCancelOn$CancelSubscriber.request(FluxCancelOn.java:111)
	at reactor.core.publisher.LambdaSubscriber.onSubscribe(LambdaSubscriber.java:119)
	at reactor.core.publisher.FluxCancelOn$CancelSubscriber.onSubscribe(FluxCancelOn.java:70)
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onSubscribe(FluxDoFinally.java:117)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:171)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:171)
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:171)
	at reactor.core.publisher.UnicastProcessor.subscribe(UnicastProcessor.java:422)
	at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:53)
	at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8134)
	at reactor.core.publisher.Flux.subscribeWith(Flux.java:8298)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8105)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8032)
	at reactor.core.publisher.Flux.subscribe(Flux.java:7950)

Recently, I found a way to trigger this by subscribing on a cancelled stream twice, here’s a reproducer.

  @Test
  public void testCancellation() {
    TcpServerTransport serverTransport = TcpServerTransport.create("localhost", 0);

    CloseableChannel server =
        RSocketFactory.receive()
            .acceptor((setup, rsocket) -> Mono.just(new EchoRSocket()))
            .transport(serverTransport)
            .start()
            .block(Duration.ofSeconds(10));

    TcpClientTransport transport = TcpClientTransport.create(server.address());

    RSocket client =
        RSocketFactory.connect().transport(transport).start().block(Duration.ofSeconds(10));

    Flux<Payload> channel = client.requestChannel(Flux.just(ByteBufPayload.create("foo")));
    Flux<Payload> channel = client.requestChannel(Flux.just(ByteBufPayload.create("foo")));
    channel.subscribe().dispose();
    // operates on a released payload
    channel.subscribe();
  }

However, I’m not entirely sure how a patch for this would look like. IIUC, cancelling Flux requests all elements, and the same payload gets processed twice after being released. However, maybe it’s expected behaviour since the stream is cancelled.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
OlegDokukacommented, Mar 19, 2020

@SerCeMan This is kind of a known issue related to requestChannel impl, which is incorrect #736. I’m working on the fix

1reaction
OlegDokukacommented, Apr 28, 2020

@SerCeMan should be fixed in RC7. Let us know if you get the same issue again

Read more comments on GitHub >

github_iconTop Results From Across the Web

NullPointerException in native java code while performing ...
If it never happens with a serial stream, this tells me that something in your code is not thread-safe. This means it doesn't...
Read more >
Still a nullpointer exception thrown on shutdown while flushing ...
I found a closed issue and replied there but decided to open one myself because although they're related they're slightly different.
Read more >
A Beginner Tutorial on Java Streams
This statelessness facilitates parallel execution of streams. Failure of ensuring statelessness can result in wrong result. Non-Interference.
Read more >
NullPointerException (Java Platform SE 8 ) - Oracle Help Center
Thrown when an application attempts to use null in a case where an object is required. These include: ... Applications should throw instances...
Read more >
Getting grpc exception `java.lang.NullPointerException ...
We have an app with dozens of bi-directional grpc streams. When cancelling one of our jobs (but leaving the bi-directional streams open), we ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found