How to fix Error thrown in Suspense without Error Boundary in React

ReactINTERMEDIATEHIGHUpdated Dec 10, 2025· 135 views

Suspense catches loading states but not errors—without an Error Boundary, thrown promises and component errors will crash your app. Wrap Suspense with ErrorBoundary to gracefully handle both loading and error states.

Quick fix

Fixes Error thrown in Suspense without Error Boundary

npm install react-error-boundary
  1. Wrap Suspense with an Error Boundary
  2. Implement a custom Error Boundary if not using a library
  3. Configure error handling in data fetching libraries
  4. Ensure proper Error Boundary positioning
react — error
npm install react-error-boundary
Error thrown in Suspense without Error Boundary
shell
npm install react-error-boundary

What this error means

Suspense is a React feature that lets you pause rendering while data loads, displaying a fallback UI in the meantime. However, Suspense only handles loading states—it cannot catch or handle errors that occur during async operations. When a promise rejects or a component within Suspense throws an error, React needs an Error Boundary to catch it. Without an Error Boundary wrapping your Suspense, the error propagates up and crashes your entire application or component tree. This error occurs because you're relying on Suspense alone to manage both loading and error states, but Suspense is not designed to catch errors. You need to pair Suspense with React's Error Boundary component to create a robust error handling pattern.

Typical symptoms

  • Application crashes when an async operation fails inside Suspense
  • Error appears in console: 'Error: Unhandled promise rejection' or similar
  • UI goes blank when data fetching fails instead of showing error message
  • Parent error boundaries catch the error instead of letting Suspense handle it gracefully
  • Development mode shows red error overlay despite Suspense being present
  • Race conditions where errors are thrown but not caught by any boundary

Common causes

  1. Suspense component is used without a parent Error Boundary to catch promise rejections
  2. Using data fetching libraries (SWR, TanStack Query) inside Suspense without error boundary configuration
  3. Custom data fetching logic throws errors that Suspense cannot handle
  4. Misunderstanding Suspense's role—it only manages loading states, not errors
  5. Error Boundary exists but is positioned outside Suspense, creating a gap in error coverage
  6. Using Suspense with async/await or fetch() without proper error handling

How to fix "Error thrown in Suspense without Error Boundary"

1Wrap Suspense with an Error Boundary

The primary solution is to nest your Suspense component inside an Error Boundary. You can use React's built-in Error Boundary API or the popular react-error-boundary library.

Using react-error-boundary:

bash
npm install react-error-boundary
jsx
import { ErrorBoundary } from "react-error-boundary";
import { Suspense } from "react";

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <p>Something went wrong loading this data:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

export function MyComponent() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <Suspense fallback={<div>Loading...</div>}>
        <DataComponent />
      </Suspense>
    </ErrorBoundary>
  );
}
2Implement a custom Error Boundary if not using a library

If you prefer not to use an external library, create a class-based Error Boundary component:

jsx
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    console.error("Error caught by boundary:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div>
          <h2>Something went wrong</h2>
          <p>{this.state.error?.message}</p>
          <button onClick={() => this.setState({ hasError: false })}>
            Try again
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

export function MyComponent() {
  return (
    <ErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <DataComponent />
      </Suspense>
    </ErrorBoundary>
  );
}
3Configure error handling in data fetching libraries

If using SWR or TanStack Query, ensure error boundaries are enabled. These libraries can throw errors into Suspense which then need to be caught.

SWR Example:

jsx
import useSWR from "swr";
import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

function DataComponent() {
  const { data, error } = useSWR("/api/data", fetcher, {
    suspense: true, // Enable Suspense
    useErrorBoundary: true, // Enable error boundary integration
  });

  return <div>{data.name}</div>;
}

export function MyComponent() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <Suspense fallback={<div>Loading...</div>}>
        <DataComponent />
      </Suspense>
    </ErrorBoundary>
  );
}

TanStack Query Example:

jsx
import { useQuery } from "@tanstack/react-query";
import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";

function DataComponent() {
  const { data, error } = useQuery({
    queryKey: ["data"],
    queryFn: fetchData,
    suspense: true, // Enable Suspense
    throwOnError: true, // Throw errors into error boundary
  });

  return <div>{data.name}</div>;
}

export function MyComponent() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <Suspense fallback={<div>Loading...</div>}>
        <DataComponent />
      </Suspense>
    </ErrorBoundary>
  );
}
4Ensure proper Error Boundary positioning

Error Boundaries must be positioned in your component tree so they wrap the Suspense boundary. The order matters:

✓ Correct - Error Boundary wraps Suspense:

jsx
<ErrorBoundary>
  <Suspense fallback={<Loading />}>
    <DataComponent />
  </Suspense>
</ErrorBoundary>

✗ Wrong - Suspense wraps Error Boundary:

jsx
<Suspense fallback={<Loading />}>
  <ErrorBoundary>
    <DataComponent />
  </ErrorBoundary>
</Suspense>

The Error Boundary must be the outer wrapper so it can catch errors thrown from within Suspense.

5Test error handling with intentional errors

Verify your Error Boundary is properly configured by testing with an intentional error:

jsx
function TestComponent() {
  const [shouldError, setShouldError] = React.useState(false);

  if (shouldError) {
    throw new Error("Test error in Suspense");
  }

  return (
    <div>
      <p>Data loaded successfully</p>
      <button onClick={() => setShouldError(true)}>
        Trigger Error
      </button>
    </div>
  );
}

export function MyComponent() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <Suspense fallback={<div>Loading...</div>}>
        <TestComponent />
      </Suspense>
    </ErrorBoundary>
  );
}

Click the button to verify your error boundary catches and displays the error properly.

Advanced notes

Error Boundary Limitations:
Error Boundaries only catch errors in the render method and lifecycle methods. Errors thrown in event handlers, async callbacks, or setTimeout must be caught separately. For those cases, use try-catch blocks or reject the promise so Suspense can catch it.

Development vs Production:
In development mode, React displays an error overlay even when an Error Boundary catches the error. This is intentional—you can dismiss it with the X button. In production, the Error Boundary's fallback UI will be shown instead.

Suspense in Next.js:
When using Suspense in Next.js server components, error handling works differently. Server component errors require a separate error.tsx file at the segment level, while client component Suspense errors need Error Boundaries as described above.

Avoiding Common Pitfalls:
- Don't put the Error Boundary inside the Suspense
- Don't use try-catch around Suspense in the JSX
- Ensure your data fetching library is configured to throw errors (useErrorBoundary option)
- Remember that Suspense only works with code that throws promises, not with traditional callbacks

Frequently asked questions

What does "Error thrown in Suspense without Error Boundary" mean?
Suspense is a React feature that lets you pause rendering while data loads, displaying a fallback UI in the meantime. However, Suspense only handles loading states—it cannot catch or handle errors that occur during async operations. When a promise rejects or a component within Suspense throws an error, React needs an Error Boundary to catch it.
How do I fix "Error thrown in Suspense without Error Boundary"?
Suspense catches loading states but not errors—without an Error Boundary, thrown promises and component errors will crash your app. Wrap Suspense with ErrorBoundary to gracefully handle both loading and error states.
What causes "Error thrown in Suspense without Error Boundary"?
Suspense component is used without a parent Error Boundary to catch promise rejections Using data fetching libraries (SWR, TanStack Query) inside Suspense without error boundary configuration Custom data fetching logic throws errors that Suspense cannot handle
Is the "Error thrown in Suspense without Error Boundary" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading