@@ -13,6 +13,7 @@ import type {RouteItem} from 'components/Layout/getRouteMeta';
1313import { GetStaticPaths , GetStaticProps , InferGetStaticPropsType } from 'next' ;
1414import { ErrorDecoderContext } from 'components/ErrorDecoderContext' ;
1515import compileMDX from 'utils/compileMDX' ;
16+ import fallbackErrorCodes from 'utils/errorCodesFallback.json' ;
1617
1718interface ErrorDecoderProps {
1819 errorCode : string | null ;
@@ -95,14 +96,61 @@ function reviveNodeOnClient(parentPropertyName: unknown, val: any) {
9596 */
9697let cachedErrorCodes : Record < string , string > | null = null ;
9798
99+ const ERROR_CODES_URL =
100+ 'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json' ;
101+
102+ /**
103+ * Fetch and cache the error codes map from GitHub.
104+ *
105+ * The raw GitHub endpoint occasionally responds with a non-JSON body (e.g.
106+ * `404: Not Found` or a rate-limit message). Calling `.json()` on those bodies
107+ * throws and, since this runs during `getStaticProps`/`getStaticPaths`, fails
108+ * the entire build. Validate the response and retry a few times so a transient
109+ * hiccup doesn't break the build.
110+ */
111+ async function fetchErrorCodes ( ) : Promise < Record < string , string > > {
112+ if ( cachedErrorCodes ) {
113+ return cachedErrorCodes ;
114+ }
115+
116+ const maxAttempts = 3 ;
117+ let lastError : unknown ;
118+ for ( let attempt = 1 ; attempt <= maxAttempts ; attempt ++ ) {
119+ try {
120+ const res = await fetch ( ERROR_CODES_URL ) ;
121+ if ( ! res . ok ) {
122+ throw new Error ( `Unexpected status ${ res . status } fetching error codes` ) ;
123+ }
124+ const text = await res . text ( ) ;
125+ const parsed = JSON . parse ( text ) ;
126+ if ( parsed == null || typeof parsed !== 'object' ) {
127+ throw new Error ( 'Error codes response was not a JSON object' ) ;
128+ }
129+ cachedErrorCodes = parsed as Record < string , string > ;
130+ return cachedErrorCodes ;
131+ } catch ( error ) {
132+ lastError = error ;
133+ if ( attempt < maxAttempts ) {
134+ await new Promise ( ( resolve ) => setTimeout ( resolve , 500 * attempt ) ) ;
135+ }
136+ }
137+ }
138+
139+ // Network is unreachable or kept returning an invalid body. Fall back to the
140+ // bundled snapshot so the build still succeeds instead of failing outright.
141+ console . warn (
142+ `Failed to fetch React error codes from ${ ERROR_CODES_URL } after ${ maxAttempts } attempts (${
143+ lastError instanceof Error ? lastError . message : String ( lastError )
144+ } ); using bundled fallback.`
145+ ) ;
146+ cachedErrorCodes = fallbackErrorCodes as Record < string , string > ;
147+ return cachedErrorCodes ;
148+ }
149+
98150export const getStaticProps : GetStaticProps < ErrorDecoderProps > = async ( {
99151 params,
100152} ) => {
101- const errorCodes : { [ key : string ] : string } = ( cachedErrorCodes ||= await (
102- await fetch (
103- 'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json'
104- )
105- ) . json ( ) ) ;
153+ const errorCodes = await fetchErrorCodes ( ) ;
106154
107155 const code = typeof params ?. errorCode === 'string' ? params ?. errorCode : null ;
108156 if ( code && ! errorCodes [ code ] ) {
@@ -141,11 +189,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
141189 /**
142190 * Fetch error codes from GitHub
143191 */
144- const errorCodes = ( cachedErrorCodes ||= await (
145- await fetch (
146- 'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json'
147- )
148- ) . json ( ) ) ;
192+ const errorCodes = await fetchErrorCodes ( ) ;
149193
150194 const paths = Object . keys ( errorCodes ) . map ( ( code ) => ( {
151195 params : {
0 commit comments