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