What am I to make of this stack trace? (see thread...
# compose
t
What am I to make of this stack trace? (see thread)
🧵 1
Copy code
Exception in thread "AWT-EventQueue-0" java.lang.StringIndexOutOfBoundsException: begin 2, end 16, length 14
	at java.base/java.lang.String.checkBoundsBeginEnd(Unknown Source)
	at java.base/java.lang.String.substring(Unknown Source)
	at androidx.compose.ui.text.AnnotatedString.subSequence(AnnotatedString.kt:116)
	at androidx.compose.foundation.text.selection.SelectionManagerKt.getCurrentSelectedText(SelectionManager.kt:895)
	at androidx.compose.foundation.text.selection.SelectionManager.getSelectedText$foundation(SelectionManager.kt:413)
	at androidx.compose.foundation.text.selection.SelectionManager.copy$foundation(SelectionManager.kt:429)
	at androidx.compose.foundation.text.selection.SelectionManager$modifier$4.invoke-ZmokQxo(SelectionManager.kt:131)
	at androidx.compose.foundation.text.selection.SelectionManager$modifier$4.invoke(SelectionManager.kt:129)
	at androidx.compose.ui.input.key.KeyInputNode.onKeyEvent-ZmokQxo(KeyInputModifier.kt:80)
	at androidx.compose.ui.focus.FocusOwnerImpl.dispatchKeyEvent-ZmokQxo(FocusOwnerImpl.kt:200)
	at androidx.compose.ui.platform.SkiaBasedOwner.sendKeyEvent-ZmokQxo(SkiaBasedOwner.skiko.kt:211)
	at androidx.compose.ui.ComposeScene.sendKeyEvent-ZmokQxo(ComposeScene.skiko.kt:822)
	at androidx.compose.ui.awt.ComposeBridge$onKeyEvent$1.invoke(ComposeBridge.desktop.kt:283)
	at androidx.compose.ui.awt.ComposeBridge$onKeyEvent$1.invoke(ComposeBridge.desktop.kt:279)
	at androidx.compose.ui.awt.ComposeBridge.catchExceptions(ComposeBridge.desktop.kt:150)
	at androidx.compose.ui.awt.ComposeBridge.onKeyEvent(ComposeBridge.desktop.kt:279)
	at androidx.compose.ui.awt.ComposeBridge.access$onKeyEvent(ComposeBridge.desktop.kt:64)
	at androidx.compose.ui.awt.ComposeBridge$attachComposeToComponent$6.keyReleased(ComposeBridge.desktop.kt:259)
	at java.desktop/java.awt.Component.processKeyEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
I think it happened when I had some text selected and then more text appeared in the view
s
Probably quite hard to debug without knowing what your code looks like
s
Linking an entire repo without where exactly the error is happening is a bit too much imo. It would take me minutes even to find where I should possibly be looking at and I could still be wrong.
t
yeah, likewise I have no idea where I should be looking because the stack trace I got doesn't contain any of my code in the first place
maybe throw a stack trace containing something that makes it look like it's my own problem, so that I have something to investigate in my own code?
s
I would start changing dependency versions up to see if that does anything. Or start stripping away code from where the crash happens and so on.
t
mmmm
the most I can gather is some text is selected and then the view refreshes because the data changed live, and maybe the selection is now invalid somehow but causes a crash instead of deselecting it
maybe a smaller test program can do it
s
That sounds like a plausible explanation indeed
t
it's maddening because it happens in the app with 100% reproducibility but a new app with just random text values thrown in doesn't do it
pretty much, run the app, select some text, copy, crash
copy causes it to add a new row because the clipboard updates
but the crash is coming directly from the selection manager so I doubt the clipboard is needed to reproduce it
well, ok, I got a test program to crash
Copy code
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.darkColors
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
import kotlinx.coroutines.delay
import kotlin.random.Random

enum class Action {
    ADD, REMOVE;

    companion object {
        fun random() = entries[Random.nextInt(entries.size)]
    }
}

fun main() = singleWindowApplication {
    val rowItems = remember { mutableStateListOf<String>() }

    LaunchedEffect(Unit) {
        while (true) {
            delay(1000)
            rowItems.add("longer text item")
            delay(1000)
            rowItems.add(0, "shorter")

            delay(1000)
            rowItems.clear()
        }
    }

    MaterialTheme(colors = darkColors()) {
        Surface(modifier = Modifier.fillMaxSize()) {
            Box(modifier = Modifier.padding(8.dp)) {
                SelectionContainer {
                    LazyColumn {
                        items(count = rowItems.size) { rowIndex ->
                            val rowItem = rowItems[rowIndex]
                            Text(text = "Item: $rowItem")
                        }
                    }
                }
            }
        }
    }

}
the timing required: • run app • select text when one row is visible • press Ctrl-C when two rows are visible
result:
Copy code
Exception in thread "AWT-EventQueue-0" java.lang.StringIndexOutOfBoundsException: begin 9, end 22, length 13
	at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3319)
	at java.base/java.lang.String.substring(String.java:1874)
	at androidx.compose.ui.text.AnnotatedString.subSequence(AnnotatedString.kt:116)
	at androidx.compose.foundation.text.selection.SelectionManagerKt.getCurrentSelectedText(SelectionManager.kt:895)
	at androidx.compose.foundation.text.selection.SelectionManager.getSelectedText$foundation(SelectionManager.kt:413)
	at androidx.compose.foundation.text.selection.SelectionManager.copy$foundation(SelectionManager.kt:429)
	at androidx.compose.foundation.text.selection.SelectionManager$modifier$4.invoke-ZmokQxo(SelectionManager.kt:131)
	at androidx.compose.foundation.text.selection.SelectionManager$modifier$4.invoke(SelectionManager.kt:129)
	at androidx.compose.ui.input.key.KeyInputNode.onKeyEvent-ZmokQxo(KeyInputModifier.kt:80)
	at androidx.compose.ui.focus.FocusOwnerImpl.dispatchKeyEvent-ZmokQxo(FocusOwnerImpl.kt:200)
	at androidx.compose.ui.platform.SkiaBasedOwner.sendKeyEvent-ZmokQxo(SkiaBasedOwner.skiko.kt:211)
	at androidx.compose.ui.ComposeScene.sendKeyEvent-ZmokQxo(ComposeScene.skiko.kt:822)
	at androidx.compose.ui.awt.ComposeBridge$onKeyEvent$1.invoke(ComposeBridge.desktop.kt:283)
	at androidx.compose.ui.awt.ComposeBridge$onKeyEvent$1.invoke(ComposeBridge.desktop.kt:279)
	at androidx.compose.ui.awt.ComposeBridge.catchExceptions(ComposeBridge.desktop.kt:150)
	at androidx.compose.ui.awt.ComposeBridge.onKeyEvent(ComposeBridge.desktop.kt:279)
	at androidx.compose.ui.awt.ComposeBridge.access$onKeyEvent(ComposeBridge.desktop.kt:64)
	at androidx.compose.ui.awt.ComposeBridge$attachComposeToComponent$6.keyPressed(ComposeBridge.desktop.kt:258)
	at java.desktop/java.awt.Component.processKeyEvent(Component.java:6593)
	at java.desktop/java.awt.Component.processEvent(Component.java:6412)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
	at java.desktop/java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1950)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:870)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1139)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:1009)
	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:835)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4892)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
is there a way to programmatically drive selection so I can make it more reproducible?
I half expected SelectionContainer to take a state object but it does not
s
I don't think there's something on the SelectionContainer to drive it by state (could be wrong), the only thing I know is that there's the BasicTextField overload which takes up a selection range, like
Copy code
val textFieldValue by remember {
  mutableStateOf(TextFieldValue(text = "asd", selection = TextRange(1, 2)))
}
BasicTextField(value = textFieldValue, {})
But I suppose that wouldn't make a difference since here you're reproing with
Text
not
TextField
. In any case, that looks like a great repro! If you can also make sure that you are on the latest alpha-beta version of where it comes from, which atm seems to be 1.7.0-beta05 https://maven.google.com/web/index.html?q=androidx.compose.ui#androidx.compose.ui:ui-text then you got yourself a great thing to report over at https://issuetracker.google.com/issues/new?component=779818&amp;template=1371638