diff --git a/apps/web/app/pools/[id]/error.test.tsx b/apps/web/app/pools/[id]/error.test.tsx
new file mode 100644
index 0000000..746e709
--- /dev/null
+++ b/apps/web/app/pools/[id]/error.test.tsx
@@ -0,0 +1,45 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import PoolDetailError from './error';
+
+vi.mock('next/link', () => ({
+ default: ({
+ href,
+ children,
+ className,
+ }: {
+ href: string;
+ children: React.ReactNode;
+ className?: string;
+ }) => (
+
+ {children}
+
+ ),
+}));
+
+describe('PoolDetailError', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('renders the error message with a back link', () => {
+ const retry = vi.fn();
+ render();
+
+ expect(screen.getByText('Something went wrong')).toBeInTheDocument();
+ expect(screen.getByText(/couldn't load this pool/)).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: /all pools/i })).toHaveAttribute(
+ 'href',
+ '/pools',
+ );
+ });
+
+ it('calls unstable_retry when the retry button is clicked', () => {
+ const retry = vi.fn();
+ render();
+
+ fireEvent.click(screen.getByRole('button', { name: /try again/i }));
+ expect(retry).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/apps/web/app/pools/[id]/error.tsx b/apps/web/app/pools/[id]/error.tsx
new file mode 100644
index 0000000..62dbae9
--- /dev/null
+++ b/apps/web/app/pools/[id]/error.tsx
@@ -0,0 +1,53 @@
+'use client';
+
+import { useEffect } from 'react';
+import Link from 'next/link';
+
+export default function PoolDetailError({
+ error,
+ unstable_retry,
+}: {
+ error: Error & { digest?: string };
+ unstable_retry: () => void;
+}) {
+ useEffect(() => {
+ console.error('Pool detail page error:', error);
+ }, [error]);
+
+ return (
+
+
+
+
+ Something went wrong
+
+
+ We couldn't load this pool. This might be a temporary issue.
+
+
+
+
+ );
+}
diff --git a/apps/web/app/pools/error.test.tsx b/apps/web/app/pools/error.test.tsx
new file mode 100644
index 0000000..369b0f6
--- /dev/null
+++ b/apps/web/app/pools/error.test.tsx
@@ -0,0 +1,21 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import { describe, it, expect, vi } from 'vitest';
+import PoolsError from './error';
+
+describe('PoolsError', () => {
+ it('renders the error message', () => {
+ const retry = vi.fn();
+ render();
+
+ expect(screen.getByText('Something went wrong')).toBeInTheDocument();
+ expect(screen.getByText(/couldn't load the pools list/)).toBeInTheDocument();
+ });
+
+ it('calls unstable_retry when the retry button is clicked', () => {
+ const retry = vi.fn();
+ render();
+
+ fireEvent.click(screen.getByRole('button', { name: /try again/i }));
+ expect(retry).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/apps/web/app/pools/error.tsx b/apps/web/app/pools/error.tsx
new file mode 100644
index 0000000..b8cefdf
--- /dev/null
+++ b/apps/web/app/pools/error.tsx
@@ -0,0 +1,34 @@
+'use client';
+
+import { useEffect } from 'react';
+
+export default function PoolsError({
+ error,
+ unstable_retry,
+}: {
+ error: Error & { digest?: string };
+ unstable_retry: () => void;
+}) {
+ useEffect(() => {
+ console.error('Pools page error:', error);
+ }, [error]);
+
+ return (
+
+
+
+ Something went wrong
+
+
+ We couldn't load the pools list. This might be a temporary issue.
+
+
+
+
+ );
+}