Handling errors: ErrorBoundary
If an error happens in a component — for example, the server did not respond — the whole page breaks without protection. An error boundary (ErrorBoundary) catches errors inside it and shows a fallback UI in place of the broken part, while the rest of the page keeps working.
ErrorBoundary
// src/App.jsx
import { ErrorBoundary } from 'solid-js';
import PostList from './components/PostList';
export default function App() {
return (
<main>
<h1>Blog</h1>
<ErrorBoundary fallback={<p>Could not load posts.</p>}>
<PostList />
</ErrorBoundary>
</main>
);
}If PostList throws an error, "Could not load posts." appears instead of the list, and the "Blog" heading stays in place.
A loading error
fetch does not treat a 404 or 500 response as an error, so you check the status yourself and throw:
// src/components/PostList.jsx
import { createResource, For } from 'solid-js';
const fetchPosts = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/postss');
if (!res.ok) throw new Error(`Server error: ${res.status}`);
return res.json();
};
export default function PostList() {
const [posts] = createResource(fetchPosts);
return (
<ul>
<For each={posts()}>{(post) => <li>{post.title}</li>}</For>
</ul>
);
}The address has a deliberate typo, postss, so the server returns 404. The resource goes into the error state, and reading posts() passes the error to the nearest ErrorBoundary.
Message and retry
You can pass a function to fallback. It receives the error and a reset function that renders the boundary's content again:
// src/App.jsx
import { ErrorBoundary } from 'solid-js';
import PostList from './components/PostList';
export default function App() {
return (
<ErrorBoundary
fallback={(err, reset) => (
<div>
<p>{err.message}</p>
<button onClick={reset}>Try again</button>
</div>
)}
>
<PostList />
</ErrorBoundary>
);
}The page shows "Server error: 404" and a button. After you fix the address in fetchPosts, clicking the button renders PostList again.
Together with Suspense
| Component | What it shows |
|---|---|
Suspense | Fallback content while data is loading |
ErrorBoundary | Fallback content if loading or rendering failed |
They are usually used together: ErrorBoundary outside, Suspense inside, and the data component deeper still.
What is not caught
ErrorBoundary catches errors during rendering, in effects and in resources. Errors in event handlers, such as onClick, do not reach it — handle them with an ordinary try...catch inside the handler.
Common mistake
Wrapping the entire app in a single ErrorBoundary. Then an error in a small comments widget replaces the whole page with a message. Put boundaries around independent parts: the post list, the comments, the sidebar.