{"record":{"id":"a8b4f14bc5d8d438","repo":"GitbookIO/gitbook","slug":"failed-to-fetch-openapi-file","errorCode":null,"errorMessage":"Failed to fetch OpenAPI file","messagePattern":"Failed to fetch OpenAPI file","errorType":"exception","errorClass":"DataFetcherError","httpStatus":null,"severity":"error","filePath":"packages/gitbook/src/lib/openapi/fetch.ts","lineNumber":120,"sourceCode":"        // If the error is not an OpenAPIParseError or DataFetcherError,\n        // we assume it's an unknown error and return a generic error.\n        console.error('Unknown error while fetching OpenAPI file:', error);\n        return { error: { code: 'invalid' as const, message: 'Unknown error' } };\n    }\n}\n\nasync function fetchFilesystemNoCache(url: string) {\n    console.log(url);\n    // Wrap the raw string to prevent invalid URLs from being passed to fetch.\n    // This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch:\n    // https://github.com/cloudflare/workerd/issues/1957\n    const response = await fetch(new URL(url), {\n        ...noCacheFetchOptions,\n        cache: 'no-store',\n    });\n\n    if (!response.ok) {\n        throw new DataFetcherError('Failed to fetch OpenAPI file', response.status);\n    }\n\n    const text = await response.text();\n    const { filesystem } = await parseOpenAPI({ value: text, rootURL: url });\n    const richFilesystem = await enrichFilesystem(filesystem);\n\n    return richFilesystem;\n}\n","sourceCodeStart":102,"sourceCodeEnd":129,"githubUrl":"https://github.com/GitbookIO/gitbook/blob/db67585ee243d063c459a855988f21612cea9c95/packages/gitbook/src/lib/openapi/fetch.ts#L102-L129","documentation":"fetchFilesystemNoCache downloads an OpenAPI/Swagger file with fetch (no-store) and throws DataFetcherError('Failed to fetch OpenAPI file', response.status) whenever the response is not ok. The HTTP status of the upstream fetch becomes the error status, so a 404 file gives a 404 error and a 500 origin gives a 500.","triggerScenarios":"Rendering an OpenAPI block whose source URL returns non-2xx — file moved or deleted (404), private/gated requiring auth (401/403), origin down (5xx), or DNS/TLS failures that surface as non-ok proxy responses.","commonSituations":"Spec URLs pointing to internal hosts unreachable from the deployment (Vercel/Cloudflare can't reach localhost or VPN-only hosts); a repo renamed so raw.githubusercontent links 404; auth-protected spec files; typos in the URL configured in the GitBook block.","solutions":["curl -I the exact spec URL from your deployment environment to see the real status code","Fix or update the source URL in the OpenAPI block to a publicly reachable endpoint","If the spec requires auth, expose it through a proxy that injects credentials, or make it public","Catch DataFetcherError around fetchFilesystem and render a friendly 'spec unavailable' state instead of failing the page"],"exampleFix":"// before\nconst filesystem = await fetchFilesystem(url);\n\n// after\ntry {\n    const filesystem = await fetchFilesystem(url);\n} catch (e) {\n    if (e instanceof DataFetcherError && e.message === 'Failed to fetch OpenAPI file') {\n        return renderSpecUnavailable(url);\n    }\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight the spec URL from the same environment\nconst head = await fetch(url, { method: 'HEAD' });\nif (!head.ok) throw new Error(`Spec unreachable: ${head.status}`);","typeGuard":"function isOpenAPIFetchError(e: unknown): e is DataFetcherError {\n    return e instanceof DataFetcherError && e.message === 'Failed to fetch OpenAPI file';\n}","tryCatchPattern":"try {\n    const fs = await fetchFilesystem(url);\n} catch (e) {\n    if (isOpenAPIFetchError(e)) {\n        return renderSpecUnavailable(url, e.status);\n    }\n    throw e;\n}","preventionTips":["Verify spec URLs are publicly reachable from your hosting region (not localhost/VPN)","Set up uptime monitoring on spec URLs used in published docs","Cache parsed filesystems so a transient upstream failure doesn't break every page load"],"tags":["openapi","fetch","upstream","http-status"],"backgroundTag":"http-request-failed","analyzedSha":"db67585ee243d063c459a855988f21612cea9c95","analyzedAt":"2026-08-28T17:49:47.831Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}