A Material3 TopAppBar action button (e.g. a navigationIcon back arrow, or an actions icon)
is rejected by click/press with:
Selector id=header-action resolved to an off-screen element and is not safe to click
…even though the button is plainly on-screen — uiautomator dump reports it inside the
display, and a raw adb shell input tap on the same point activates it.
The trigger is the idiomatic Android layout Scaffold { topBar = TopAppBar{…} } { Column(Modifier.verticalScroll(…)) {…} }. snapshot -i models the whole screen as the scrolling
Column ([scroll-area] [scrollable]) and folds the app bar into content above scroll-area hidden, so the off-screen guard treats the app-bar icons as outside the scroll viewport.
- agent-device 0.20.0 (also reproduces on 0.19.3)
- Android emulator, API 35 (Pixel 8), 1080×2400
- Jetpack Compose BOM 2026.06.01, Material3,
androidx.activity1.13.0,compileSdk36 /targetSdk35 - Kotlin 2.4.0, AGP 8.13.2 (the bug is layout-structural, not version-specific)
./repro.sh # builds, installs, drives agent-device, asserts the mismatchRequires one running Android emulator/device, the Android SDK, and Node (for npx agent-device).
### ground truth — header-action IS on-screen
screen 1080x2400
header-action bounds: [944,154][1070,280] # top-right, well inside the display
### agent-device snapshot -i
@e1 [scroll-area] [scrollable]
[content above scroll-area hidden] # <-- the TopAppBar is folded in here
[content below scroll-area hidden]
### click a content row (inside the scroll area)
Tapped id=row-3 (540, 668) # works
### click the TopAppBar action
Error (COMMAND_FAILED): Selector id=header-action resolved to an off-screen element and is not safe to click
### raw `adb shell input tap 1007 217` (center of header-action)
text="last tap: header-action" # the app registers it fine — not an app bug
click id=header-action should tap the button (as the raw tap and uiautomator confirm it is
on-screen and hittable), the same way it taps content rows.
The screen is a bare ComponentActivity (no Nav3, no ViewModel — see
MainActivity.kt):
Scaffold(
topBar = { TopAppBar(actions = { IconButton(Modifier.testTag("header-action")) { … } }) }
) { padding ->
Column(Modifier.fillMaxSize().padding(padding).verticalScroll(rememberScrollState())) { … }
}
Column(Modifier.verticalScroll(...))content →snapshot -ireports[scroll-area]+content above scroll-area hidden, andclick id=header-actionis refused as off-screen.- Swap that one line for a
LazyColumn→snapshot -ilists the rows flat (no "content above" folding) and the same header tap succeeds.
Not required to reproduce: Nav3 / NavDisplay, isTraversalGroup/paneTitle, a collapsing
LargeTopAppBar. A plain TopAppBar above a verticalScroll Column is enough. The repro uses
enableEdgeToEdge() (the modern targetSdk 35 default); whether that is required was not tested.
"TopAppBar above a scrolling content column" is one of the most common Android screen shapes, and
a top-bar back/overflow/action icon is often the only way to leave or act on a screen. Under this
layout those actions can't be driven by selector/@ref, and the only workaround is a raw
coordinate tap (which defeats self-locating, resolution-independent flows).
- #1075 — introduced "refuse off-screen selector taps" (the guard raising this message).
- #1366 / #1374 — open work on the off-screen-rejection guard (recovery in scrollable forms). This report is a different facet: a non-scrolled app-bar action, above the scroll area, being classified as hidden/off-screen.