hakimel/reveal.js · error · Error

HTTP status ${response.status}

Error message

HTTP status ${response.status}

What it means

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.

Source

Thrown at react/src/components/markdown.tsx:138

	const [loadedMarkdown, setLoadedMarkdown] = useState<string | null>(null);
	const [loadError, setLoadError] = useState<string | null>(null);

	useEffect(() => {
		if (!src) {
			setLoadedMarkdown(null);
			setLoadError(null);
			return;
		}

		const abortController = new AbortController();
		setLoadedMarkdown(null);
		setLoadError(null);

		void (async () => {
			try {
				const response = await fetch(src, { signal: abortController.signal });
				if (!response.ok) {
					throw new Error(`HTTP status ${response.status}`);
				}

				const source = charset
					? new TextDecoder(charset).decode(await response.arrayBuffer())
					: await response.text();

				setLoadedMarkdown(source);
			} catch (error) {
				if (abortController.signal.aborted) return;
				setLoadError(getErrorMessage(error));
			}
		})();

		return () => abortController.abort();
	}, [src, charset]);

	const slideAttributes = getSlideAttributes(rest, {
		background,

View on GitHub (pinned to a3b9406956)

Solutions

  1. Open the src URL directly in a browser/network tab and confirm it returns 200; fix the path or deploy the missing file.
  2. 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).
  3. Match the runtime base URL — if the app is served from a subpath, prefix src accordingly or use a relative URL.
  4. 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.
  5. Render the loadError state in your UI so the failure is visible rather than silent.

Example fix

// before — relative path breaks under a subpath deployment
<Markdown src="./slides/intro.md" />

// after — resolve against the app base, or import the asset
import introUrl from './slides/intro.md?url';
<Markdown src={introUrl} />
Defensive patterns

Strategy: validation

Validate before calling

async function assertMarkdownReachable(src, charset) {
  const res = await fetch(src, { method: 'GET' });
  if (!res.ok) throw new Error(`Markdown src unreachable: HTTP ${res.status}`);
  return src;
}

Type guard

function isProbablyValidSrc(src) {
  try {
    const u = new URL(src, window.location.href);
    return u.protocol === 'http:' || u.protocol === 'https:' || u.protocol === 'data:';
  } catch {
    return false;
  }
}

Try / catch

// The component already catches internally; surface loadError in your UI
<Markdown src={src} onErrorRender={(msg) => <p>Could not load slide: {msg}</p>} />

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of hakimel/reveal.js@a3b9406956 (2026-08-12). Data as JSON: /api/errors/e59d29b070837237. Report an issue: GitHub.