Streaming short pieces of text into a textarea causes a crash

John Hendrikx john.hendrikx at gmail.com
Tue Dec 19 09:18:44 UTC 2023


It looks like you are manipulating a property that is bound to a UI 
control on an external thread.

Property manipulations that are tied to controls that are part of an 
active (visible) Scene **must** be done on the FX thread.

Try:

     StreamingResponseHandler<AiMessage> streamingResponseHandler = new 
StreamingResponseHandler<>() {
                 @Override
                 public void onNext(String token) {
                     Platform.runLater(() -> 
searchAction.appendAnswer(token));
                 }
     }

--John

On 19/12/2023 09:14, Frank Delporte wrote:
>
>     Hi, while experimenting with a ChatGPT-like user interface, I
>     found a crashing JVM with different types of errors when streaming
>     the response towards a TextArea. This is probably caused by too
>     fast refreshes of the text as pieces of content are received
>     within the same milliseconds:
>
>     19/12/2023 08:51:57.874 | DocsAnswerService                   |
>     onNext               | INFO     | Appending ' better'
>     19/12/2023 08:51:57.874 | DocsAnswerService                   |
>     onNext               | INFO     | Appending ' performance'
>     19/12/2023 08:51:57.875 | DocsAnswerService                   |
>     onNext               | INFO     | Appending ' after'
>     19/12/2023 08:51:57.978 | DocsAnswerService                   |
>     onNext               | INFO     | Appending ' the'
>     19/12/2023 08:51:57.979 | DocsAnswerService                   |
>     onNext               | INFO     | Appending ' first'
>     19/12/2023 08:51:57.979 | DocsAnswerService                   |
>     onNext               | INFO     | Appending ' and'
>
>     But even when collecting this pieces of text to e.g. minimum 255
>     characters to reduce the number of TextArea changes, errors
>     happen. So it's not clear how to prevent this as I can't define
>     the threshold to be used...
>
>     Dummy code causing the crash:
>
>     public class SearchAction {
>         private final StringProperty answer;
>         ...
>         public StringProperty getAnswerProperty() {
>             return answer;
>         }
>
>         public void appendAnswer(String token) {
>             this.answer.set(this.answer.getValue() + token);
>         }
>     }
>
>     TextArea lastAnswer = new TextArea();
>     lastAnswer.textProperty().bind(searchAction.getAnswerProperty());
>
>     StreamingResponseHandler<AiMessage> streamingResponseHandler = new
>     StreamingResponseHandler<>() {
>                 @Override
>                 public void onNext(String token) {
>                     searchAction.appendAnswer(token);
>                 }
>     }
>
>     *Fatal Error *
>
>     #
>     # A fatal error has been detected by the Java Runtime Environment:
>     #
>     #  SIGBUS (0xa) at pc=0x000000013f53b630, pid=13013, tid=80715
>     #
>     # JRE version: OpenJDK Runtime Environment Zulu21.30+15-CA
>     (21.0.1+12) (build 21.0.1+12-LTS)
>     # Java VM: OpenJDK 64-Bit Server VM Zulu21.30+15-CA
>     (21.0.1+12-LTS, mixed mode, sharing, tiered, compressed oops,
>     compressed class ptrs, g1 gc, bsd-aarch64)
>     # Problematic frame:
>     # j
>     javafx.scene.text.Text.queryAccessibleAttribute(Ljavafx/scene/AccessibleAttribute;[Ljava/lang/Object;)Ljava/lang/Object;+576
>     javafx.graphics at 21.0.1
>     #
>     # No core dump will be written. Core dumps have been disabled. To
>     enable core dumping, try "ulimit -c unlimited" before starting
>     Java again
>     #
>     # An error report file with more information is saved as:
>     # /Users/frankdelporte/GitLab/docs-langchain4j/hs_err_pid13013.log
>     Exception in thread "JavaFX Application Thread"
>     java.lang.StackOverflowError: Delayed StackOverflowError due to
>     ReservedStackAccess annotated method
>     at
>     javafx.graphics/com.sun.glass.ui.mac.MacAccessible.NSAccessibilityPostNotification(Native
>     Method)
>     at
>     javafx.graphics/com.sun.glass.ui.mac.MacAccessible.sendNotification(MacAccessible.java:816)
>     at
>     javafx.graphics/javafx.scene.Node.notifyAccessibleAttributeChanged(Node.java:10004)
>     at
>     javafx.graphics/javafx.scene.text.Text$TextAttribute$12.invalidated(Text.java:1847)
>     at
>     javafx.base/javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
>     at
>     javafx.base/javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:148)
>     at
>     javafx.graphics/javafx.scene.text.Text.setCaretPosition(Text.java:961)
>     at javafx.graphics/javafx.scene.text.Text$3.invalidated(Text.java:466)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:145)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:50)
>     at javafx.graphics/javafx.scene.text.Text.setText(Text.java:444)
>     at
>     javafx.controls/javafx.scene.control.skin.TextAreaSkin.lambda$new$16(TextAreaSkin.java:347)
>     at
>     javafx.controls/com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler.lambda$new$2(LambdaMultiplePropertyChangeListenerHandler.java:95)
>     at
>     javafx.base/javafx.beans.WeakInvalidationListener.invalidated(WeakInvalidationListener.java:82)
>     at
>     javafx.base/com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:360)
>     at
>     javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:91)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1496)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1500)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl$TextProperty.controlContentHasChanged(TextInputControl.java:1439)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl.lambda$new$0(TextInputControl.java:176)
>     at
>     javafx.base/com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:147)
>     at
>     javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:91)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl$ContentBase.fireValueChangedEvent(TextInputControl.java:149)
>     at
>     javafx.controls/javafx.scene.control.TextArea$TextAreaContent.insert(TextArea.java:214)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:1301)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl.filterAndSet(TextInputControl.java:1266)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl$TextProperty.doSet(TextInputControl.java:1517)
>     at
>     javafx.controls/javafx.scene.control.TextInputControl$TextProperty$Listener.invalidated(TextInputControl.java:1540)
>     at
>     javafx.base/com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:360)
>     at
>     javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:91)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:104)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:111)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:145)
>     at
>     javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:50)
>     at
>     com.azul.docs.langchain4j.SearchAction.appendAnswer(SearchAction.java:45)
>     at
>     com.azul.docs.langchain4j.DocsAnswerService$2.onNext(DocsAnswerService.java:172)
>     at
>     dev.langchain4j.model.openai.OpenAiStreamingChatModel.handle(OpenAiStreamingChatModel.java:152)
>     at
>     dev.langchain4j.model.openai.OpenAiStreamingChatModel.lambda$generate$0(OpenAiStreamingChatModel.java:133)
>     at
>     dev.ai4j.openai4j.StreamingRequestExecutor$2.onEvent(StreamingRequestExecutor.java:178)
>     at
>     okhttp3.internal.sse.RealEventSource.onEvent(RealEventSource.kt:101)
>     at
>     okhttp3.internal.sse.ServerSentEventReader.completeEvent(ServerSentEventReader.kt:108)
>     at
>     okhttp3.internal.sse.ServerSentEventReader.processNextEvent(ServerSentEventReader.kt:52)
>     at
>     okhttp3.internal.sse.RealEventSource.processResponse(RealEventSource.kt:75)
>     at
>     okhttp3.internal.sse.RealEventSource.onResponse(RealEventSource.kt:46)
>     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
>     at
>     java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
>     at
>     java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
>     at java.base/java.lang.Thread.run(Thread.java:1583)
>     [93.499s][warning][os] Loading hsdis library failed
>     #
>     # If you would like to submit a bug report, please visit:
>     # http://www.azul.com/support/
>     # The crash happened outside the Java Virtual Machine in native code.
>     # See problematic frame for where to report the bug.
>     #
>
>     Process finished with exit code 134 (interrupted by signal 6:SIGABRT)
>
>     *Error #1*
>
>     Exception in thread "JavaFX Application Thread"
>     java.lang.NullPointerException: Cannot read field "advances"
>     because "this.layoutCache" is null
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.shape(PrismTextLayout.java:919)
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1113)
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:230)
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:256)
>     at
>     javafx.graphics/javafx.scene.text.Text.getLogicalBounds(Text.java:432)
>     at
>     javafx.graphics/javafx.scene.text.Text.doComputeGeomBounds(Text.java:1186)
>     at
>     javafx.graphics/javafx.scene.text.Text$1.doComputeGeomBounds(Text.java:149)
>     at
>     javafx.graphics/com.sun.javafx.scene.shape.TextHelper.computeGeomBoundsImpl(TextHelper.java:90)
>     at
>     javafx.graphics/com.sun.javafx.scene.NodeHelper.computeGeomBounds(NodeHelper.java:117)
>     at javafx.graphics/javafx.scene.Node.updateGeomBounds(Node.java:3812)
>     at javafx.graphics/javafx.scene.Node.getGeomBounds(Node.java:3774)
>     at javafx.graphics/javafx.scene.Node.getLocalBounds(Node.java:3722)
>     at
>     javafx.graphics/javafx.scene.Node$MiscProperties$3.computeBounds(Node.java:6812)
>     at
>     javafx.graphics/javafx.scene.Node$LazyBoundsProperty.get(Node.java:9749)
>     at
>     javafx.graphics/javafx.scene.Node$LazyBoundsProperty.get(Node.java:9740)
>     at javafx.graphics/javafx.scene.Node.getBoundsInLocal(Node.java:3402)
>     at
>     javafx.controls/javafx.scene.control.skin.TextAreaSkin$ContentView.layoutChildren(TextAreaSkin.java:1325)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1208)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1215)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1215)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1215)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1215)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1215)
>     at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1215)
>     at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:594)
>     at
>     javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2600)
>     at
>     javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:401)
>     at
>     java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
>     at
>     javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:400)
>     at
>     javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:430)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:592)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:572)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:565)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:352)
>     at
>     javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
>
>     *Error #2*
>
>     Exception in thread "JavaFX Application Thread"
>     java.lang.NullPointerException: Cannot read the array length
>     because "this.lines" is null
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.layout(PrismTextLayout.java:1316)
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.ensureLayout(PrismTextLayout.java:230)
>     at
>     javafx.graphics/com.sun.javafx.text.PrismTextLayout.getBounds(PrismTextLayout.java:256)
>     at
>     javafx.graphics/javafx.scene.text.Text.getLogicalBounds(Text.java:432)
>     at
>     javafx.graphics/javafx.scene.text.Text.doComputeGeomBounds(Text.java:1186)
>     at
>     javafx.graphics/javafx.scene.text.Text$1.doComputeGeomBounds(Text.java:149)
>     at
>     javafx.graphics/com.sun.javafx.scene.shape.TextHelper.computeGeomBoundsImpl(TextHelper.java:90)
>     at
>     javafx.graphics/com.sun.javafx.scene.NodeHelper.computeGeomBounds(NodeHelper.java:117)
>     at javafx.graphics/javafx.scene.Node.updateGeomBounds(Node.java:3812)
>     at javafx.graphics/javafx.scene.Node.getGeomBounds(Node.java:3774)
>     at javafx.graphics/javafx.scene.Node.getLocalBounds(Node.java:3722)
>     at javafx.graphics/javafx.scene.Node.updateTxBounds(Node.java:3876)
>     at
>     javafx.graphics/javafx.scene.Node.getTransformedBounds(Node.java:3668)
>     at javafx.graphics/javafx.scene.Node.updateBounds(Node.java:776)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at javafx.graphics/javafx.scene.Parent.updateBounds(Parent.java:1834)
>     at
>     javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2615)
>     at
>     javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:401)
>     at
>     java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
>     at
>     javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:400)
>     at
>     javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:430)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:592)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:572)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:565)
>     at
>     javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:352)
>     at
>     javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
>
>     Best regards
>     Frank Delporte
>
>     /Want to have coding-fun? /
>     /Check my blog //https://webtechie.be//
>     <https://webtechie.be/>/and book "Getting started with Java on
>     Raspberry Pi" on //https://webtechie.be/books//
>     <https://webtechie.be/books/>
>
>
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20231219/7d916645/attachment-0001.htm>


More information about the openjfx-dev mailing list