Skip to content

[Worklets] Tried to modify key 'value' … warnings + thrown non-worklet function 'addListener' on the UI thread with react-native-worklets 0.8 (Reanimated 4 / RN 0.85 / New Architecture) #1470

@augustosamame

Description

@augustosamame

Description

When any component using KeyboardProvider / KeyboardAwareScrollView mounts, the dev console is flooded with
Reanimated/Worklets warnings, and a worklet throws in development:

[Worklets] Tried to synchronously call a non-worklet function `addListener` on the UI thread.

This happens on both iOS and Android, on app startup (the providers wrap the root), and repeats on every screen
that mounts a keyboard-aware view. The app remains functional (the thrown error is shown as a dev redbox/LogBox), but
it makes development very noisy and is non-suppressible from app code, since the throw originates inside
react-native-worklets.

Environment

Package Version
react-native-keyboard-controller 1.21.8
react-native 0.85.3
react-native-reanimated 4.3.1
react-native-worklets 0.8.3
react-native-screens 4.25.1
react-native-safe-area-context 5.7.0
react 19.2.3
expo 56.0.3 (SDK 56)
Architecture New Architecture (Fabric/bridgeless), Hermes
Platforms iOS (Simulator + device) and Android (emulator)
Babel babel-preset-expo (injects react-native-worklets/plugin automatically; confirmed not double-applied)

Steps to reproduce

  1. Expo SDK 56 / RN 0.85 app with the New Architecture, Reanimated 4.3.1 + Worklets 0.8.3.
  2. Wrap the app root in <KeyboardProvider> and render any screen using KeyboardAwareScrollView (e.g. a simple
    login form).
  3. Run a dev build (expo run:ios / expo run:android) and open the screen.

Minimal component:

import { KeyboardProvider, KeyboardAwareScrollView } from 'react-native-keyboard-controller';

export default function App() {
  return (
    <KeyboardProvider>
      <KeyboardAwareScrollView>
        <TextInput placeholder="email" />
        <TextInput placeholder="password" secureTextEntry />
      </KeyboardAwareScrollView>
    </KeyboardProvider>
  );
}

Expected behavior

Keyboard-aware scrolling works with no Worklets warnings or thrown errors.

Actual behavior

A burst of warnings (8+ per mount):

WARN  [Worklets] Tried to modify key `value` of an object which has been already passed to a worklet.
https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-modify-key-of-an-object-which
-has-been-converted-to-a-serializable

followed by a thrown error:

ERROR  [Error: [Worklets] Tried to synchronously call a non-worklet function `addListener` on the UI thread.
https://docs.swmansion.com/react-native-worklets/docs/guides/troubleshooting#tried-to-synchronously-call-a-non-workle
t-function-on-the-ui-thread]

A representative call-stack frame points at valueUnpacker (worklet value deserialization on the UI runtime).

Investigation / likely cause

Both messages originate in react-native-worklets 0.8:

  • "Tried to modify key 'value' …"logger.warn in
    react-native-worklets/lib/module/memory/serializable.native.js (~line 542).
  • "… non-worklet function 'addListener' on the UI thread" → thrown in
    react-native-worklets/lib/module/threads.native.js (~line 188; in dev a remote/JS function called on the UI runtime
    throws to point users at runOnJS).

It appears the keyboard handler captures the FocusedInputEvents event-emitter object (which exposes addListener)
into a worklet/shared value, and worklets 0.8's stricter serialization then (a) warns when that captured object is
mutated, and (b) throws when addListener is invoked during unpacking on the UI thread. The relevant site in this
package — react-native-keyboard-controller/lib/module/animated.js:

import Reanimated, { useSharedValue } from "react-native-reanimated";
import { FocusedInputEvents, /* ... */ } from "./bindings";
// ...
const progressSV = useSharedValue(0);
const heightSV   = useSharedValue(0);
const layout     = useSharedValue(null);
// ...
const subscription = FocusedInputEvents.addListener("layoutDidSynchronize", () => { /* ... */ });

(plus several "worklet" handlers in the same file). This pattern worked under older worklets versions but trips
worklets 0.8's serialization rules under the New Architecture.

Workaround

configureReanimatedLogger({ strict: false }) quiets the warnings but not the thrown error. We replaced
KeyboardAwareScrollView/KeyboardProvider with a small wrapper over React Native's KeyboardAvoidingView +
ScrollView, which avoids worklets entirely.

Additional notes

  • Reproduces with the exact versions Expo SDK 56 pins (expo install reports them as up to date), so it isn't a
    user version mismatch.
  • Dev-only (__DEV__) — release builds don't surface the messages, but the underlying worklet behavior is still a
    smell.
  • Ruled out: verified a single instance of react, react-native, react-native-reanimated, and react-native-worklets
    (single hoisted copy, no nested duplicates, no self-reference symlinks, default Metro resolver, Yarn 1 workspace).
    So this is not the duplicate-instance / self-referencing-package class of issue that's commonly blamed for these
    worklet errors.
  • Happy to provide a minimal reproducible repo if helpful.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions