@@ -127,17 +127,28 @@ const App: FunctionComponent<AppProps> = ({
127127 const awaitingEmailVerificationStatus =
128128 ! ! authenticatedUser && ! emailVerificationStatusKnown && ! aal2Required ;
129129
130+ /**
131+ * A `redirectTo` that points at the page we're already on is a no-op we must
132+ * ignore. `getInitialProps` re-runs on every navigation — including the
133+ * same-URL `router.replace`s this effect performs — and `useRouter()` returns
134+ * a fresh object each time, so honouring such a redirect spins forever in a
135+ * `replace` -> `getInitialProps` -> `replace` loop (e.g. landing on `/` after
136+ * accepting an org invite, where a stale `redirectTo: "/"` kept re-firing).
137+ */
138+ const pendingRedirect =
139+ ! ! redirectTo && redirectTo !== router . asPath ? redirectTo : undefined ;
140+
130141 /**
131142 * Handle client-side redirects that were determined in getInitialProps.
132143 * On the server these are HTTP 307s; on the client getInitialProps returns
133144 * a `redirectTo` prop instead, and this effect performs the navigation after
134145 * the current route transition completes (avoiding NProgress stalls).
135146 */
136147 useEffect ( ( ) => {
137- if ( redirectTo ) {
138- void router . replace ( redirectTo ) ;
148+ if ( pendingRedirect ) {
149+ void router . replace ( pendingRedirect ) ;
139150 }
140- } , [ redirectTo , router ] ) ;
151+ } , [ pendingRedirect , router ] ) ;
141152
142153 useEffect ( ( ) => {
143154 setSentryUser ( { authenticatedUser } ) ;
@@ -167,8 +178,15 @@ const App: FunctionComponent<AppProps> = ({
167178 // router.query is empty during server-side rendering for pages that don’t use
168179 // getServerSideProps. By showing app skeleton on the server, we avoid UI
169180 // mismatches during rehydration and improve type-safety of param extraction.
170- // We also gate on `redirectTo` so the page doesn't flash before navigating.
171- if ( ssr || ! router . isReady || awaitingEmailVerificationStatus || redirectTo ) {
181+ // We also gate on a pending redirect so the page doesn't flash before
182+ // navigating. A `redirectTo` matching the current path isn't pending (see
183+ // `pendingRedirect`), so we render rather than stall on the loading state.
184+ if (
185+ ssr ||
186+ ! router . isReady ||
187+ awaitingEmailVerificationStatus ||
188+ pendingRedirect
189+ ) {
172190 return < Suspense /> ; // Replace with app skeleton
173191 }
174192
0 commit comments