{"record":{"id":"e59d29b070837237","repo":"hakimel/reveal.js","slug":"http-status-response-status","errorCode":null,"errorMessage":"HTTP status ${response.status}","messagePattern":"HTTP status (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"react/src/components/markdown.tsx","lineNumber":138,"sourceCode":"\tconst [loadedMarkdown, setLoadedMarkdown] = useState<string | null>(null);\n\tconst [loadError, setLoadError] = useState<string | null>(null);\n\n\tuseEffect(() => {\n\t\tif (!src) {\n\t\t\tsetLoadedMarkdown(null);\n\t\t\tsetLoadError(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tsetLoadedMarkdown(null);\n\t\tsetLoadError(null);\n\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(src, { signal: abortController.signal });\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP status ${response.status}`);\n\t\t\t\t}\n\n\t\t\t\tconst source = charset\n\t\t\t\t\t? new TextDecoder(charset).decode(await response.arrayBuffer())\n\t\t\t\t\t: await response.text();\n\n\t\t\t\tsetLoadedMarkdown(source);\n\t\t\t} catch (error) {\n\t\t\t\tif (abortController.signal.aborted) return;\n\t\t\t\tsetLoadError(getErrorMessage(error));\n\t\t\t}\n\t\t})();\n\n\t\treturn () => abortController.abort();\n\t}, [src, charset]);\n\n\tconst slideAttributes = getSlideAttributes(rest, {\n\t\tbackground,","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/hakimel/reveal.js/blob/a3b940695648aa1c5b0680bc9a5b905cf43020e5/react/src/components/markdown.tsx#L120-L156","documentation":"The Markdown component (react/src/components/markdown.tsx:136) fetches the src URL and throws `HTTP status ${response.status}` whenever response.ok is false (:137). The throw is caught inside the same async IIFE (:146) and surfaced as loadError state (rendered to the user), so it does not crash the app — it is the component's way of turning a non-2xx response into a visible error message. A network/CORS/abort failure takes a different path: it reaches the catch as a TypeError and is also funneled into loadError via getErrorMessage.","triggerScenarios":"Passing a src that returns 404 (wrong path / file not deployed), 403/401 (auth required), 500 (server error), a redirect chain ending in an error, or any non-2xx status; dev-server base path mismatch; loading a markdown file that was not copied to the build output dir.","commonSituations":"Public-path misconfiguration after moving from '/' to a subpath; markdown file excluded from the bundler's asset pipeline; deploying without copying the .md; pointing at a CMS/endpoint that requires auth headers the fetch does not send; environment difference (works locally, 404 in prod).","solutions":["Open the src URL directly in a browser/network tab and confirm it returns 200; fix the path or deploy the missing file.","Ensure the markdown asset is emitted/copied by your build (e.g. place it in the public/ dir or import it so the bundler hashes and serves it).","Match the runtime base URL — if the app is served from a subpath, prefix src accordingly or use a relative URL.","If the endpoint requires auth/headers, fetch the markdown yourself and pass the string via children instead of src, since the component's fetch sends no custom headers.","Render the loadError state in your UI so the failure is visible rather than silent."],"exampleFix":"// before — relative path breaks under a subpath deployment\n<Markdown src=\"./slides/intro.md\" />\n\n// after — resolve against the app base, or import the asset\nimport introUrl from './slides/intro.md?url';\n<Markdown src={introUrl} />","handlingStrategy":"validation","validationCode":"async function assertMarkdownReachable(src, charset) {\n  const res = await fetch(src, { method: 'GET' });\n  if (!res.ok) throw new Error(`Markdown src unreachable: HTTP ${res.status}`);\n  return src;\n}","typeGuard":"function isProbablyValidSrc(src) {\n  try {\n    const u = new URL(src, window.location.href);\n    return u.protocol === 'http:' || u.protocol === 'https:' || u.protocol === 'data:';\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"// The component already catches internally; surface loadError in your UI\n<Markdown src={src} onErrorRender={(msg) => <p>Could not load slide: {msg}</p>} />","preventionTips":["Import the .md through your bundler (e.g. ?url / ?raw) so the served path is always correct.","Confirm the asset is emitted to your build output and served at the runtime base path.","Render the component's loadError state so HTTP failures are visible in QA, not swallowed.","If the endpoint needs auth or custom headers, fetch the markdown yourself and pass the string via children instead of src."],"tags":["network","fetch","http","markdown","react-wrapper"],"backgroundTag":null,"analyzedSha":"a3b940695648aa1c5b0680bc9a5b905cf43020e5","analyzedAt":"2026-08-12T23:46:52.821Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}