AppSync MaxSubscriptionsReachedError in react 18 strictmode even when unsubscribing
See original GitHub issueBefore opening, please confirm:
- I have searched for duplicate or closed issues and discussions.
- I have read the guide for submitting bug reports.
- I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
Not applicable
Amplify APIs
GraphQL API
Amplify Categories
api
Environment information
# Put output below this line
System:
OS: macOS 12.6
CPU: (10) arm64 Apple M1 Max
Memory: 8.58 GB / 32.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 18.8.0 - /opt/homebrew/bin/node
Yarn: 1.22.19 - ~/node_modules/.bin/yarn
npm: 8.18.0 - /opt/homebrew/bin/npm
Watchman: 2022.08.22.00 - /opt/homebrew/bin/watchman
Browsers:
Chrome: 105.0.5195.125
Safari: 15.6.1
npmPackages:
@ampproject/toolbox-optimizer: undefined ()
@apollo/client: ^3.6.9 => 3.6.9
@apollo/client/cache: undefined ()
@apollo/client/core: undefined ()
@apollo/client/errors: undefined ()
@apollo/client/link/batch: undefined ()
@apollo/client/link/batch-http: undefined ()
@apollo/client/link/context: undefined ()
@apollo/client/link/core: undefined ()
@apollo/client/link/error: undefined ()
@apollo/client/link/http: undefined ()
@apollo/client/link/persisted-queries: undefined ()
@apollo/client/link/retry: undefined ()
@apollo/client/link/schema: undefined ()
@apollo/client/link/subscriptions: undefined ()
@apollo/client/link/utils: undefined ()
@apollo/client/link/ws: undefined ()
@apollo/client/react: undefined ()
@apollo/client/react/components: undefined ()
@apollo/client/react/context: undefined ()
@apollo/client/react/hoc: undefined ()
@apollo/client/react/hooks: undefined ()
@apollo/client/react/parser: undefined ()
@apollo/client/react/ssr: undefined ()
@apollo/client/testing: undefined ()
@apollo/client/testing/core: undefined ()
@apollo/client/utilities: undefined ()
@apollo/client/utilities/globals: undefined ()
@aws-amplify/cli: ^10.0.0 => 10.0.0
@babel/core: undefined ()
@babel/runtime: 7.15.4
@edge-runtime/primitives: 1.1.0-beta.31
@hapi/accept: undefined ()
@napi-rs/triples: undefined ()
@next/react-dev-overlay: undefined ()
@segment/ajv-human-errors: undefined ()
@types/node: 18.7.23 => 18.7.23
@types/react: 18.0.21 => 18.0.21
@types/react-dom: 18.0.6 => 18.0.6
@vercel/nft: undefined ()
acorn: undefined ()
add: ^2.0.6 => 2.0.6
amphtml-validator: undefined ()
amplify: ^0.0.11 => 0.0.11
arg: undefined ()
assert: undefined ()
async-retry: undefined ()
async-sema: undefined ()
aws-amplify: ^4.3.36 => 4.3.36
aws-appsync: ^4.1.7 => 4.1.7
aws-appsync-react: ^4.0.13 => 4.0.13
babel-packages: undefined ()
browserify-zlib: undefined ()
browserslist: undefined ()
buffer: undefined ()
bytes: undefined ()
chalk: undefined ()
ci-info: undefined ()
cli-select: undefined ()
codegen: ^0.1.0 => 0.1.0
comment-json: undefined ()
compression: undefined ()
conf: undefined ()
constants-browserify: undefined ()
content-disposition: undefined ()
content-type: undefined ()
cookie: undefined ()
cross-spawn: undefined ()
crypto-browserify: undefined ()
cssnano-simple: undefined ()
debug: undefined ()
devalue: undefined ()
domain-browser: undefined ()
edge-runtime: undefined ()
eslint: 8.24.0 => 8.24.0
eslint-config-next: 12.3.1 => 12.3.1
events: undefined ()
find-cache-dir: undefined ()
find-up: undefined ()
fresh: undefined ()
get-orientation: undefined ()
glob: undefined ()
graphql: ^16.6.0 => 16.6.0 (15.8.0)
graphql-ws: ^5.11.2 => 5.11.2
gzip-size: undefined ()
http-proxy: undefined ()
https-browserify: undefined ()
icss-utils: undefined ()
ignore-loader: undefined ()
image-size: undefined ()
is-animated: undefined ()
is-docker: undefined ()
is-wsl: undefined ()
jest-worker: undefined ()
json5: undefined ()
jsonwebtoken: undefined ()
loader-utils: undefined ()
lodash.curry: undefined ()
lru-cache: undefined ()
micromatch: undefined ()
mini-css-extract-plugin: undefined ()
nanoid: undefined ()
native-url: undefined ()
neo-async: undefined ()
next: 12.3.1 => 12.3.1
node-fetch: undefined ()
node-html-parser: undefined ()
ora: undefined ()
os-browserify: undefined ()
p-limit: undefined ()
path-browserify: undefined ()
postcss-flexbugs-fixes: undefined ()
postcss-modules-extract-imports: undefined ()
postcss-modules-local-by-default: undefined ()
postcss-modules-scope: undefined ()
postcss-modules-values: undefined ()
postcss-preset-env: undefined ()
postcss-safe-parser: undefined ()
postcss-scss: undefined ()
postcss-value-parser: undefined ()
prettier: 2.7.1 => 2.7.1
process: undefined ()
punycode: undefined ()
querystring-es3: undefined ()
raw-body: undefined ()
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
react-is: 17.0.2
react-refresh: 0.12.0
react-server-dom-webpack: undefined ()
regenerator-runtime: 0.13.4
sass-loader: undefined ()
schema-utils: undefined ()
semver: undefined ()
send: undefined ()
setimmediate: undefined ()
source-map: undefined ()
stream-browserify: undefined ()
stream-http: undefined ()
string-hash: undefined ()
string_decoder: undefined ()
strip-ansi: undefined ()
tar: undefined ()
terser: undefined ()
text-table: undefined ()
timers-browserify: undefined ()
tty-browserify: undefined ()
typescript: 4.8.3 => 4.8.3
ua-parser-js: undefined ()
unistore: undefined ()
util: undefined ()
vm-browserify: undefined ()
watchpack: undefined ()
web-vitals: undefined ()
webpack: undefined ()
webpack-sources: undefined ()
ws: undefined ()
npmGlobalPackages:
alfred-fkill: 0.4.1
firebase-tools: 11.3.0
npm-check-updates: 14.1.1
npm: 8.18.0
particle-cli: 3.1.0
react-native-asset: 2.0.1
wscat: 5.2.0
yarn: 1.22.19
Describe the bug
When subscribing to max connections in React 18+, strictmode will force unmount and remount the component. I am unsubscribing in the cleanup, but the remount, and reconnect will cause MaxSubscriptionsReachedError. If the unsubscribe is happening outside of the cleanup in the useeffect, it will work. This seems like a race condition maybe?
Expected behavior
Component connects to 100, component unmounts and unsubscribes from 100. Component mounts and resubscribes with no error.
Reproduction steps
- use react 18+ with strictmode
- create component with useeffect hook
- add code below
Code Snippet
// Put your code below this line.
useEffect(() => {
let subs: ZenObservable.Subscription[] = [];
for (let i = 0; i < 100; i++) {
console.log("subscribing", i);
const sub = API.graphql<
GraphQLSubscription<typeof subscribeToNewMessage>
>(
graphqlOperation(subscribeToNewMessage, {
conversationId: `myNewId${i}`,
})
);
const s = sub.subscribe({
next: (data) => {
console.log(">>>>>>", data);
},
});
subs.push(s);
}
return () => {
subs.forEach((s) => s.unsubscribe());
};
}, []);
Log output
// Put your logs below this line
"errors":[{"message":"Connection failed: {\"errors\":{\"errorType\":\"MaxSubscriptionsReachedError\",\"message\":\"Max number of 100 subscriptions reached\"}}"
aws-exports.js
No response
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
chrome
Mobile Browser Version
No response
Additional information and screenshots
No response
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:5 (4 by maintainers)
Top Results From Across the Web
Strict Mode - React
StrictMode is a tool for highlighting potential problems in an application. Like Fragment , StrictMode does not render any visible UI.
Read more >Using strict mode in React 18: A guide to its new behaviors
In this article, you'll learn about Strict Mode, its various features, and how the v18 release has improved its API.
Read more >React 18 useEffect Double Call for APIs: Emergency Fix
Fix 2: Remove Strict Mode #. It is strict mode that is causing the double render, so another option is just to remove...
Read more >record_transformer filter doesn't work from included directory
AppSync MaxSubscriptionsReachedError in react 18 strictmode even when unsubscribing, 5, 2022-10-01, 2022-12-03. Amplify push fails with error addressing ...
Read more >React 18 strict mode causing component to render twice
React StrictMode calls all Effects twice to make sure their ... You may need to change your effects accordingly, even if they have...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Here is the Component being used:
Findings
Reproducing the issue
The issue could be reproduced using the following schema:
The following error is displayed in the console 100 times when strict mode is used and the unsubscribe of all subscriptions is inside of the cleanup function:
The error doesn’t display in the console when the unsubscribe of all subscriptions is inside of the cleanup function.
Note: The issue is not displaying either using React 17, both with the unsubscribe inside or outside of the cleanup function.
Looking deeper into the error
The error is caused whenever a subscription query is sent to the API and the maximum number of subscriptions is used (100).
Something odd is happening with the error handling. As said by @josephp27, “if the unsubscribe is happening outside of the cleanup in the
useeffect
, it will work”. It is working because the error is being handled by a callback function. But there is an error response from the API.With the help of VSCode debugger, I placed a breakpoint in
node_modules/@aws-amplify/pubsub/src/Providers/AWSAppSyncRealTimeProvider/index.ts
in line 519 and configured it as a log breakpoint to display the following message:API responded with error. message.data: {message.data}
.The following error is displayed in the console 100 times when strict mode is used and the unsubscribe of all subscriptions is outside of the cleanup function:
Which is the same error, but it is not being logged by the console because it is being handled by a
subscriptionFailedCallback
.The
subscriptionFailedCallback
isundefined
whenever the unsubscribe of all subscriptions is inside of the cleanup function. This could be in fact due to a race condition.It is even said in
node_modules/@aws-amplify/pubsub/src/Providers/AWSAppSyncRealTimeProvider/index.ts
in line 312. If you look into the source code you will see:Note: This isn’t happening using React 17, both with the unsubscribe inside or outside of the cleanup function. Not even the log breakpoint is being reached.