Closed ChristopherGabba closed 11 months ago
Hi @ChristopherGabba, thank you for opening this issue. It looks like you are facing this error when performing signup with auto signin - which seems to be successful, however you get an unsubscribe error. Due to this I think the root of the issue will be somewhere in the useEffect + Hub setup.
Taking a look at the code you shared one thing I noticed is how the Hub.listener is getting cleaned up in your useEffect. Instead of invoking it directly, could you wrap it in a function?
Ex:
// Do this
return () => {
authSubscription()
}
// Instead of
return authSubscription()
@nadetastic Thanks for the response Dan. I've tried every combination of the useEffect (cleanup functions, no cleanup functions, different types, etc. )
I've also tried:
// deprecated versions
return () => Hub.remove()
return () => {
Hub.remove()
}
return () => authSubscription()
return () => {
authSubscription()
}
The cleanup you proposed above produced a slightly different stack trace but same overall error:
I spent about 5 hours trying every combination I could think of and the only thing I can determine is that I never get the error if I don't the Hub.listen()
function. If I set the token directly without the listener I never get the error. As soon as I uncomment the Hub.listen()
and try again, I get this error.
Just got a slightly different stack trace on the same code attempt.
@ChristopherGabba Could you verify the version of aws-amplify
and react-native
(or share your package.json) so I can try and reproduce this issue? I tried this out with the latest version of aws-amplify and a React Web App and don't see any errors, so im curios what could be the issue with React Native+Hub. Also are you able to confirm if this affects Android as well?
@nadetastic
// package.json
{
"name": "reel-feel",
"version": "0.0.1",
"private": true,
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "react-native start",
"ios": "react-native run-ios",
"android": "react-native run-android --active-arch-only",
"test:detox": "detox test -c ios.sim.debug",
"build:detox": "detox build -c ios.sim.debug",
"ci:test:detox": "detox test -c ios.sim.release -l verbose --cleanup",
"ci:build:detox": "detox build -c ios.sim.release",
"compile": "tsc --noEmit -p . --pretty",
"format": "prettier --write \"app/**/*.{js,jsx,json,md,ts,tsx}\"",
"lint": "eslint index.js App.js app test --fix --ext .js,.ts,.tsx && npm run format",
"patch": "patch-package",
"test": "jest",
"test:watch": "jest --watch",
"adb": "adb reverse tcp:9090 tcp:9090 && adb reverse tcp:3000 tcp:3000 && adb reverse tcp:9001 tcp:9001 && adb reverse tcp:8081 tcp:8081",
"postinstall": "node ./bin/postInstall",
"bundle:ios": "react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ios/main.jsbundle --assets-dest ios",
"bundle:android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res",
"release:ios": "echo 'Not implemented yet: release:ios. Use Xcode. More info: https://reactnative.dev/docs/next/publishing-to-app-store'",
"release:android": "cd android && rm -rf app/src/main/res/drawable-* && ./gradlew assembleRelease && cd - && echo 'APK generated in ./android/app/build/outputs/apk/release/app-release.apk'",
"clean": "npx react-native-clean-project",
"clean-all": "npx react-native clean-project-auto",
"expo:start": "expo start",
"expo:android": "expo start --android",
"expo:ios": "expo start --ios",
"expo:web": "expo start --web",
"expo:build:detox": "detox build -c ios.sim.expo",
"expo:test:detox": "./bin/downloadExpoApp.sh && detox test --configuration ios.sim.expo"
},
"overrides": {
"react-native": "0.72.5",
"react-error-overlay": "6.0.9"
},
"dependencies": {
"@aws-amplify/ui-react-native": "^1.2.28",
"@expo-google-fonts/m-plus-1p": "^0.2.3",
"@expo-google-fonts/montserrat": "^0.2.3",
"@expo-google-fonts/space-grotesk": "^0.2.2",
"@expo/config-plugins": "^7.2.5",
"@expo/metro-config": "^0.10.7",
"@gorhom/bottom-sheet": "^4.4.7",
"@likashefqet/react-native-image-zoom": "^2.1.1",
"@react-native-async-storage/async-storage": "1.18.2",
"@react-native-clipboard/clipboard": "^1.11.2",
"@react-native-community/netinfo": "9.3.10",
"@react-navigation/bottom-tabs": "^6.3.2",
"@react-navigation/native": "^6.0.2",
"@react-navigation/native-stack": "^6.0.2",
"@shopify/flash-list": "1.4.3",
"amazon-cognito-identity-js": "^6.3.6",
"apisauce": "2.1.5",
"aws-amplify": "^5.3.11",
"axios": "^1.5.0",
"cheerio": "^1.0.0-rc.12",
"date-fns": "^2.29.2",
"expo": "^49.0.7",
"expo-application": "~5.3.0",
"expo-av": "~13.4.1",
"expo-blur": "~12.4.1",
"expo-clipboard": "~4.3.1",
"expo-config-plugin-ios-share-extension": "^0.0.4",
"expo-constants": "~14.4.2",
"expo-contacts": "~12.2.0",
"expo-dev-client": "~2.4.11",
"expo-device": "~5.4.0",
"expo-file-system": "~15.4.4",
"expo-font": "~11.4.0",
"expo-image-picker": "~14.3.2",
"expo-linear-gradient": "~12.3.0",
"expo-linking": "~5.0.2",
"expo-localization": "~14.3.0",
"expo-media-library": "~15.4.1",
"expo-splash-screen": "^0.20.5",
"expo-status-bar": "~1.6.0",
"expo-video-thumbnails": "~7.4.0",
"firebase": "^10.3.1",
"i18n-js": "3.9.2",
"jsdom": "^22.1.0",
"jsdom-jscore-rn": "^0.1.8",
"lodash.filter": "^4.6.0",
"mobx": "6.6.0",
"mobx-react-lite": "3.4.0",
"mobx-state-tree": "5.1.5",
"react": "18.2.0",
"react-native": "0.72.5",
"react-native-animated-pagination-dots": "^0.1.73",
"react-native-bootsplash": "^5.0.2",
"react-native-element-dropdown": "^2.9.0",
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.12.0",
"react-native-get-random-values": "^1.9.0",
"react-native-pager-view": "6.2.0",
"react-native-reanimated": "~3.3.0",
"react-native-receive-sharing-intent": "^2.0.0",
"react-native-render-html": "^6.3.4",
"react-native-safe-area-context": "4.6.3",
"react-native-screens": "~3.22.0",
"react-native-share-menu": "^6.0.0",
"react-native-touchable-scale": "^2.2.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-vision-camera": "^3.0.0",
"react-native-volume-manager": "^1.10.0",
"react-native-webview": "13.2.2",
"react-native-youtube-iframe": "^2.3.0",
"reactotron-mst": "3.1.4",
"reactotron-react-js": "^3.3.7",
"reactotron-react-native": "5.0.3",
"typescript": "^4.9.4"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native-community/cli-platform-ios": "^8.0.2",
"@rnx-kit/metro-config": "^1.3.5",
"@rnx-kit/metro-resolver-symlinks": "^0.1.26",
"@types/i18n-js": "3.8.2",
"@types/jest": "^29.2.1",
"@types/react": "~18.2.14",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"babel-jest": "^29.2.1",
"babel-loader": "8.2.5",
"babel-plugin-root-import": "^6.6.0",
"eslint": "8.17.0",
"eslint-config-prettier": "8.5.0",
"eslint-config-standard": "17.0.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.0.0",
"eslint-plugin-react": "7.30.0",
"eslint-plugin-react-native": "4.0.0",
"fbjs-scripts": "3.0.1",
"jest": "^29.2.1",
"jest-circus": "29",
"jest-environment-node": "29",
"jest-expo": "^49.0.0",
"metro-config": "0.75.1",
"metro-react-native-babel-preset": "0.75.1",
"metro-source-map": "0.75.1",
"mocha": "^10.2.0",
"patch-package": "^6.4.7",
"postinstall-prepare": "1.0.1",
"prettier": "2.8.8",
"query-string": "^7.0.1",
"react-devtools-core": "4.24.7",
"react-dom": "18.2.0",
"react-native-web": "~0.19.6",
"react-test-renderer": "18.2.0",
"reactotron-core-client": "^2.8.10",
"regenerator-runtime": "^0.13.4",
"ts-jest": "29",
"typescript": "^5.1.3"
},
"resolutions": {
"@types/react": "^18",
"@types/react-dom": "^18"
},
"engines": {
"node": ">=18"
},
"prettier": {
"printWidth": 100,
"semi": false,
"singleQuote": false,
"trailingComma": "all"
},
"eslintConfig": {
"root": true,
"parser": "@typescript-eslint/parser",
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-native/all",
"standard",
"prettier"
],
"plugins": [
"@typescript-eslint",
"react",
"react-native"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"project": "./tsconfig.json"
},
"settings": {
"react": {
"pragma": "React",
"version": "detect"
}
},
"globals": {
"__DEV__": false,
"jasmine": false,
"beforeAll": false,
"afterAll": false,
"beforeEach": false,
"afterEach": false,
"test": false,
"expect": false,
"describe": false,
"jest": false,
"it": false
},
"rules": {
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-member-accessibility": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/indent": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-interface": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-object-literal-type-assertion": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"comma-dangle": 0,
"multiline-ternary": 0,
"no-undef": 0,
"no-unused-vars": 0,
"no-use-before-define": 0,
"no-global-assign": 0,
"quotes": 0,
"react-native/no-raw-text": 0,
"react/no-unescaped-entities": 0,
"react/prop-types": 0,
"space-before-function-paren": 0
}
}
}
I am using a dev client on a handheld device, not a simulator.
I do not own an android phone to try, but my brother does. I will try to test it out at the next opportunity I see him.
Update. When I expand the error stack trace, I see it appears to be coming from: node_modules/xstate/lib/waitFor.js
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var _tslib = require('./_virtual/_tslib.js');
var defaultWaitForOptions = {
timeout: 10000 // 10 seconds
};
/**^M
* Subscribes to an actor ref and waits for its emitted value to satisfy^M
* a predicate, and then resolves with that value.^M
* Will throw if the desired state is not reached after a timeout^M
* (defaults to 10 seconds).^M
*^M
* @example^M
* ```js^M
* const state = await waitFor(someService, state => {^M
* return state.hasTag('loaded');^M
* });^M
*^M
* state.hasTag('loaded'); // true^M
* ```^M
*^M
* @param actorRef The actor ref to subscribe to^M
* @param predicate Determines if a value matches the condition to wait for^M
* @param options^M
* @returns A promise that eventually resolves to the emitted value^M
* that matches the condition^M
*/
function waitFor(actorRef, predicate, options) {
var resolvedOptions = _tslib.__assign(_tslib.__assign({}, defaultWaitForOptions), options);
return new Promise(function (res, rej) {
var done = false;
if (process.env.NODE_ENV !== 'production' && resolvedOptions.timeout < 0) {
console.error('`timeout` passed to `waitFor` is negative and it will reject its internal promise immediately.');
}
var handle = resolvedOptions.timeout === Infinity ? undefined : setTimeout(function () {
sub.unsubscribe();
rej(new Error("Timeout of ".concat(resolvedOptions.timeout, " ms exceeded")));
}, resolvedOptions.timeout);
var dispose = function () {
clearTimeout(handle);
done = true;
sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
};
var sub = actorRef.subscribe({
next: function (emitted) {
if (predicate(emitted)) {
dispose();
res(emitted);
}
},
error: function (err) {
dispose();
rej(err);
},
complete: function () {
dispose();
rej(new Error("Actor terminated without satisfying predicate"));
}
});
if (done) {
sub.unsubscribe();
}
});
}
exports.waitFor = waitFor;
@ChristopherGabba thanks for sharing the above. From the looks of it, this may potentially be originating from the @aws-amplify/ui-react-native
package (which has a dependency to xstate
) and not the aws-amplify
JavaScript package as this doesn't have this dependency.
Can you clarify how you are using the ui-react-native package?
@nadetastic Interesting. I am only using it here to wrap my app:
import { Authenticator } from "@aws-amplify/ui-react-native"
function App(props: AppProps) {
/ * more code for app function */
return (
<Authenticator.Provider>
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<ErrorBoundary catchErrors={Config.catchErrors}>
<GestureHandlerRootView style={$rootView}>
<AppNavigator
linking={linking}
initialState={initialNavigationState}
onStateChange={onNavigationStateChange}
/>
</GestureHandlerRootView>
</ErrorBoundary>
</SafeAreaProvider>
</Authenticator.Provider>
)
}
Do I really need to wrap this with the Authentication provider if I'm doing the Auth custom from the separate aws amplify library?
import { Auth, Hub } from "aws-amplify"
I guess I probably don't...
@ChristopherGabba if you are using the useAuthenticator
hook, then yes, you would need to have the Provider in you app to wrap the hook. Otherwise, you may not need to use the Provider as it is specific to the ui library. Have you been able to get unblocked on this?
Hi @ChristopherGabba I'm going to mark this issue as closed now, but do let me know if you have any questions.
Hi @nadetastic We are getting below issue after using Auth.confirmsignup(). This confirmSignup is getting successful after 5 sec getting this error
waitFor.js:44 Uncaught TypeError: Cannot read properties of undefined (reading 'unsubscribe') at waitFor.js:44:1
Before opening, please confirm:
JavaScript Framework
React Native
Amplify APIs
Authentication
Amplify Categories
auth
Environment information
Describe the bug
Expected behavior
The app should not crash after running Auth.signUp() and this error should not occur.
Reproduction steps
Code Snippet
SIGN UP FUNCTION ON SIGN UP SCREEN:
VERIFICATION CODE SCREEN:
AUTHENTICATION LISTENER CUSTOM HOOK ON MAIN APP NAVIGATOR
Log output
aws-exports.js
Manual configuration
Additional configuration
No response
Mobile Device
iPhone12
Mobile Operating System
iOS 16.6.1
Mobile Browser
Safari
Mobile Browser Version
No response
Additional information and screenshots
I'm using an expo development build.