Skip to content

Commit 5b8a90c

Browse files
Make error-decoder build resilient to error-codes fetch failures
The /errors/[errorCode] page fetches React's error codes from GitHub raw at build time. When that endpoint returns a non-JSON body (e.g. '404: Not Found' or a rate-limit message), calling .json() throws and fails the whole build during page-data collection. Validate the response and retry a few times, and fall back to a bundled snapshot of codes.json if the fetch is still unusable, so a transient GitHub hiccup no longer breaks the build.
1 parent 274c7b3 commit 5b8a90c

2 files changed

Lines changed: 644 additions & 10 deletions

File tree

src/pages/errors/[errorCode].tsx

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {RouteItem} from 'components/Layout/getRouteMeta';
1313
import {GetStaticPaths, GetStaticProps, InferGetStaticPropsType} from 'next';
1414
import {ErrorDecoderContext} from 'components/ErrorDecoderContext';
1515
import compileMDX from 'utils/compileMDX';
16+
import fallbackErrorCodes from 'utils/errorCodesFallback.json';
1617

1718
interface ErrorDecoderProps {
1819
errorCode: string | null;
@@ -95,14 +96,61 @@ function reviveNodeOnClient(parentPropertyName: unknown, val: any) {
9596
*/
9697
let 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+
98150
export 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

Comments
 (0)