Files
dotfiles/dot_agents/skills/tanstack-query-best-practices/rules/err-error-boundaries.md
T
Prad Nukala 6406208b35 shell: fish functions -> ~/.local/bin executables + bash/zsh ports; manage ~/.agents
- 16 cross-shell utilities converted to sh/bash chezmoi executables:
  ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone
  ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj
  (ghg-clone not named ghg: unrelated cargo binary owns that name)
- cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho
  cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files
- fish keeps only shell-state functions; converted ones now hit PATH
- cp-appid ignore gating moved to .local/bin path
- dot_agents/skills: 82 skills materialized from dotstate storage so
  dot_claude skill symlinks resolve on fresh bootstrap; dotstate
  profile/symlinks.json released .agents/skills .bashrc .zshrc
2026-08-10 15:15:06 -04:00

3.6 KiB

err-error-boundaries: Use Error Boundaries with useQueryErrorResetBoundary

Priority: HIGH

Explanation

When using Suspense with TanStack Query, errors propagate to error boundaries. Use useQueryErrorResetBoundary to reset query errors when users retry, preventing stuck error states.

Bad Example

// Error boundary without query reset - retry may not work
function ErrorBoundary({ children }: { children: React.ReactNode }) {
  return (
    <ReactErrorBoundary
      fallbackRender={({ error, resetErrorBoundary }) => (
        <div>
          <p>Error: {error.message}</p>
          <button onClick={resetErrorBoundary}>Try again</button>
          {/* resetErrorBoundary alone doesn't reset query state */}
        </div>
      )}
    >
      {children}
    </ReactErrorBoundary>
  )
}

// Query error persists after retry click

Good Example

import { useQueryErrorResetBoundary } from '@tanstack/react-query'
import { ErrorBoundary } from 'react-error-boundary'

function QueryErrorBoundary({ children }: { children: React.ReactNode }) {
  const { reset } = useQueryErrorResetBoundary()

  return (
    <ErrorBoundary
      onReset={reset}
      fallbackRender={({ error, resetErrorBoundary }) => (
        <div className="error-container">
          <h2>Something went wrong</h2>
          <pre>{error.message}</pre>
          <button onClick={resetErrorBoundary}>
            Try again
          </button>
        </div>
      )}
    >
      {children}
    </ErrorBoundary>
  )
}

// Usage with Suspense
function App() {
  return (
    <QueryErrorBoundary>
      <Suspense fallback={<Loading />}>
        <Posts />
      </Suspense>
    </QueryErrorBoundary>
  )
}

function Posts() {
  // useSuspenseQuery throws on error, caught by boundary
  const { data } = useSuspenseQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts,
  })

  return <PostList posts={data} />
}

Good Example: With TanStack Router

// Route-level error handling
import { createFileRoute } from '@tanstack/react-router'
import { useQueryErrorResetBoundary } from '@tanstack/react-query'

export const Route = createFileRoute('/posts')({
  loader: ({ context: { queryClient } }) =>
    queryClient.ensureQueryData(postQueries.list()),

  errorComponent: ({ error, reset }) => {
    const { reset: resetQuery } = useQueryErrorResetBoundary()

    return (
      <div>
        <p>Failed to load posts: {error.message}</p>
        <button
          onClick={() => {
            resetQuery()
            reset()
          }}
        >
          Retry
        </button>
      </div>
    )
  },

  component: PostsPage,
})

Error Boundary Placement Strategy

// Granular error boundaries for isolated failures
function Dashboard() {
  return (
    <div className="dashboard">
      {/* Each section can fail independently */}
      <QueryErrorBoundary>
        <Suspense fallback={<Skeleton />}>
          <RecentActivity />
        </Suspense>
      </QueryErrorBoundary>

      <QueryErrorBoundary>
        <Suspense fallback={<Skeleton />}>
          <Statistics />
        </Suspense>
      </QueryErrorBoundary>

      <QueryErrorBoundary>
        <Suspense fallback={<Skeleton />}>
          <Notifications />
        </Suspense>
      </QueryErrorBoundary>
    </div>
  )
}

Context

  • useQueryErrorResetBoundary clears error state for all queries in the boundary
  • Always pair Suspense queries with error boundaries
  • Place boundaries based on failure isolation needs
  • Consider inline error handling for non-critical data
  • The reset only affects queries that were in error state