Repository navigation
[Bug]: iOS trash button does not remove a persisted environment #12012
Description
Activity
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.needs-triageIssue needs maintainer review and initial categorization.Issue needs maintainer review and initial categorization.
on Sep 16, 2026 Triage
Confirmed on current
main(935c55b37). This is a real iOS mobile bug, not a wash of #9761. A direct saved environment can be restored from Keychain after delete+reinstall, and the Environments trash control never presents its confirm, so the row cannot be forgotten.What the code does
Settings → Environments lists catalog presentations, including offline/disabled ones. A direct (non-relay) row is
ConnectionEnvironmentRow: expand, then the red trash. That is the control in this report, not the T3 Connect long-press path.Trash calls
onRemoveEnvironmentPressinapps/mobile/src/state/use-remote-environment-registry.ts. The only skip beforeAlert.alert("Remove from this device?", …)is a lookup inconnectedEnvironments. The list and the handler share that array, so a visible row should match — but the silentreturnis still a landmine (any identity/stale-closure miss eats the tap with no feedback).If the alert did show and the user confirmed, remove is real:
environmentCatalog.remove→EnvironmentRegistry.remove→removeConnectionFromCatalog→ SecureStoret3code.connection-catalog.v1.That document is why reinstall does not help. Mobile persists the catalog through Expo SecureStore / iOS Keychain (
catalog-store.ts,mobile-secure-storage.ts).app.config.tsalso setskeychain-access-groups(#3665). iOS keeps those items across delete+reinstall. Settings → Client Storage only clears thread/cache data; it does not drop the catalog.Why the confirm never appears
Two stacked presentation problems, both still on
main:- Settings → Environments is a nested formSheet.
SettingsSheetuses form-sheet presentation, then a headerless stack, then Environments. RNAlert.alertpresents aUIAlertControllerfrom the key window — a known miss insidereact-native-screensform sheets / nested nav. The confirm is invoked and never visible, which matches “tap trash, nothing happens.” Other Settings alerts sit on the sheet root; this is the only confirm on the pushed Environments screen. - The trash lives in a Reanimated
FadeInblock that mounts only after expand (ConnectionEnvironmentRow). First taps during layout/FadeIncan be dropped.
Either one is enough for a dead trash on a stale row. The Keychain restore just makes it permanent: the endpoint is offline, Off still leaves the row, reinstall brings it back, and the only forget control is the one that does not present.
First engineering step: reproduce on device/simulator — Settings formSheet → Environments → expand an offline direct row → trash. Confirm whether
Alert.alertis called and whether aUIAlertControlleris sitting behind the sheet.Related, not duplicates
Issue / PR Why it does not close this Open #9761 T3 Connect unconnected discovery rows have no trash/deregister. This report is a direct saved row that already has a trash button. Do not attribute Closes #12012.Merged #11478 Switch = disable, not remove. Updated the confirm copy. Trash is still Alert.alert+ catalog remove.Merged #11990 Marks incompatible servers unsupported and disables the switch. Not in the 2026-09-15 App Store binary. Trash stays enabled. Open #8923 Catalog backup so a decode failure does not wipe environments. Opposite problem. Merged #3665 Keychain access group. Explains why reinstall restores the row. Not the dead confirm. No open PR claims the direct-row confirm / persist path.
Suggested fix
Keep this as a bugfix on
apps/mobile(direct Environments row only):- Always present confirm. Do not
returnwhen the list lookup misses; fall back to the environment id for the label. - Present the confirm in-tree (
showConfirmDialog/ a sheet-local modal), notAlert.alert.ConfirmDialogHostalready exists because native dialogs are unreliable on one platform; the Settings formSheet needs the same treatment on iOS. - Surface a persist failure. If
SecureStore.setItem/removefails, show an error and keep the row. A successful in-memory remove plus a failed Keychain write is how a “removed” environment comes back on the next launch. - Tests: offline direct environment → trash presents confirm; confirm → catalog no longer contains that target; failed SecureStore write → error, row remains.
- Optional escape hatch in Client Storage / Diagnostics: “Forget saved environments on this device,” because Keychain survives reinstall and there is no wipe today.
Do not fold this into #9761 (relay deregister) or #8923 (catalog backup).
Workaround
None in-app. Off only silences the row. Client Storage does not drop credentials. Delete+reinstall restores the same catalog. Until a build with the fix ships, the stale direct row can only be ignored.
Classification: bug · accepted · minor–medium (iOS; cannot forget a Keychain-restored direct environment)
Labels: addaccepted,via-triage; keepbug; removeneeds-triage
Discord tags:mobile-ios,persistence,ui- Settings → Environments is a nested formSheet.
- addedacceptedfeature request acceptedfeature request acceptedvia-triageFiled through npx t3 triageFiled through npx t3 triageand removedneeds-triageIssue needs maintainer review and initial categorization.Issue needs maintainer review and initial categorization.
on Sep 16, 2026
Before submitting
Area
apps/mobile
Steps to reproduce
The stale row in this reproduction is a direct saved environment, not a T3 Connect relay environment.
Expected behavior
Tapping the trash button should present the “Remove from this device?” confirmation and, after confirmation, remove the saved environment and its local credentials/catalog data.
Actual behavior
Tapping the trash button has no visible effect: no confirmation alert appears and the environment is not removed. The behavior persists after force-quitting the app and restarting the iPhone.
The environment also survives deleting and reinstalling the app. This is consistent with the catalog being stored through Expo SecureStore/iOS Keychain (
t3code.connection-catalog.v1), whose data can survive reinstall. The current mobile handler appears intended to callAlert.alert("Remove from this device?", ...), but that alert is never presented in this state.Relevant source paths:
apps/mobile/src/state/use-remote-environment-registry.ts(onRemoveEnvironmentPress)apps/mobile/src/connection/catalog-store.tsapps/mobile/src/persistence/mobile-secure-storage.tsImpact
Minor bug or occasional failure
Version or commit
Current iOS App Store release installed 2026-09-15 (exact build not shown)
Environment
T3 Code iOS app on iPhone; direct saved environment; stale endpoint offline
Logs or stack traces
Screenshots, recordings, or supporting files
No response
Workaround
None. Force-quit, restart, and reinstall do not clear the entry because the connection catalog persists in iOS Keychain. The stale row can only be ignored.