Skip to content

🔥 [🐛] Audio recording state race #3547

@andreashermann

Description

@andreashermann

Issue

Audio recording race: early release after long-press can leave recording active and unresolved.

When using Channel + MessageInput with audio recording enabled, releasing shortly after a long-press can leave the recorder in an invalid state:

recording active
micLocked === false
recordingStopped === false
no active user interaction
no resolution (cancel / lock / send)

Recording continues indefinitely in an unlocked state.

Reproduced with default StartAudioRecordingButton
Reproduced with custom CustomStartAudioRecordingButton

This suggests the issue is in the SDK interaction lifecycle, not in custom components.

Steps to reproduce

Steps to reproduce the behavior:

  1. Long press the mic button
  2. Wait until recording starts
  3. Release immediately
  4. Recording sometimes remains active and unlocked

Expected behavior

Once recording starts, it should always resolve into one of:

  • locked
  • cancelled
  • stopped / sent

It should never remain active after the user has released the interaction.

Project Related Information

Customization

Click To Expand

<Channel
  key={channelKey}
  channel={channel}
  doSendMessageRequest={handleSendMessage}
  doUpdateMessageRequest={handleUpdateMessage}
  audioRecordingEnabled={isAudioMessagesEnabled && audioRecordingEnabled}
  asyncMessagesMinimumPressDuration={500}
  hasCommands={false}
  hasFilePicker={false}
  hasCameraPicker
  hasImagePicker
  topInset={insets.top}
  InputButtons={InputButtons}
  SendButton={CustomSendButton}
  Card={CustomCard}
  Reply={CustomReply}
  MessageError={MessageErrorWithDelay}
  NetworkDownIndicator={NetworkDownIndicator}
>
  <FilteredMessageListProvider filterMode={filterMode}>
    <MessageList
      onThreadSelect={handleThreadPress}
      setFlatListRef={(ref) => { flatListRef.current = ref; }}
      additionalFlatListProps={flatListScrollProps}
    />
    <MessageInput
      key={messageInputKey}
    />
  </FilteredMessageListProvider>
</Channel>

Offline support

  • I have enabled offline support.
  • The feature I'm having does not occur when offline support is disabled. (stripe out if not applicable)

Environment

Click To Expand

package.json:

"dependencies": {
    "@expo/vector-icons": "^15.0.2",
    "@op-engineering/op-sqlite": "^15.2.7",
    "@react-native-async-storage/async-storage": "^2.2.0",
    "@react-native-community/datetimepicker": "8.4.4",
    "@react-native-community/netinfo": "11.4.1",
    "@react-native-community/slider": "5.0.1",
    "@react-native-firebase/app": "^23.7.0",
    "@react-native-firebase/remote-config": "^23.7.0",
    "@react-navigation/native": "^7.1.8",
    "@sentry/react-native": "~7.2.0",
    "@tanstack/react-query": "^5.90.20",
    "expo": "~54.0.33",
    "expo-asset": "~12.0.12",
    "expo-audio": "~1.1.1",
    "expo-build-properties": "~1.0.10",
    "expo-clipboard": "~8.0.8",
    "expo-constants": "~18.0.13",
    "expo-dev-client": "~6.0.20",
    "expo-device": "~8.0.10",
    "expo-file-system": "~19.0.21",
    "expo-font": "~14.0.11",
    "expo-haptics": "~15.0.8",
    "expo-image-manipulator": "~14.0.8",
    "expo-image-picker": "~17.0.10",
    "expo-linear-gradient": "~15.0.8",
    "expo-linking": "~8.0.11",
    "expo-localization": "~17.0.8",
    "expo-media-library": "~18.2.1",
    "expo-notifications": "~0.32.16",
    "expo-router": "~6.0.23",
    "expo-secure-store": "~15.0.8",
    "expo-sharing": "~14.0.8",
    "expo-speech-recognition": "~3.1.2",
    "expo-splash-screen": "~31.0.13",
    "expo-status-bar": "~3.0.9",
    "expo-updates": "~29.0.16",
    "expo-video": "^3.0.16",
    "i18next": "^25.8.0",
    "intl-pluralrules": "^2.0.1",
    "libphonenumber-js": "^1.12.25",
    "mixpanel-react-native": "^3.1.3",
    "moment": "^2.30.1",
    "react": "19.1.0",
    "react-dom": "19.1.0",
    "react-i18next": "^16.5.4",
    "react-native": "0.81.5",
    "react-native-element-dropdown": "^2.12.4",
    "react-native-expo-swipe-button": "^1.0.2",
    "react-native-gesture-handler": "~2.28.0",
    "react-native-gifted-charts": "^1.4.70",
    "react-native-maps": "^1.27.1",
    "react-native-markdown-display": "^7.0.2",
    "react-native-pager-view": "^6.9.1",
    "react-native-popover-view": "^6.1.0",
    "react-native-reanimated": "~4.1.3",
    "react-native-safe-area-context": "~5.6.0",
    "react-native-screens": "~4.16.0",
    "react-native-svg": "15.12.1",
    "react-native-toast-message": "^2.3.3",
    "react-native-view-shot": "^4.0.3",
    "react-native-web": "~0.21.0",
    "react-native-webview": "13.15.0",
    "react-native-worklets": "0.5.1",
    "stream-chat-expo": "^8.13.9",
    "zustand": "^5.0.8"
  },

react-native info output:

 OUTPUT GOES HERE
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • stream-chat-react-native version you're using that has this issue:
    • 8.13.9
  • Device/Emulator info:
    • I am using a physical device
    • OS version: iOS 26.4.1
    • Device/Emulator: iPhone 17

Additional context

Screenshots

Click To Expand

  • the touch was released from the microphone icon in this recording
  • recording goes on
  • recording cannot be cancelled anymore
recording4-crop.mp4


Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions