# Tanstack Query Intent Framework Handle Status And Errors

> Use this when designing TanStack Query loading, empty, stale, background error, retry, toast, throwOnError, and Error Boundary flows. Covers status versus fetchStatus, stale data after failed refetches, global QueryCache or MutationCache error callbacks, and local versus boundary-level error handling.

- Skill: `lukasa1993/tanstack-query-intent-framework-handle-status-and-errors` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add lukasa1993/tanstack-query-intent-framework-handle-status-and-errors`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lukasa1993/tanstack-query-intent-framework-handle-status-and-errors/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: lukasa1993 (https://skillmd.com/u/lukasa1993)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lukasa1993/tanstack-query-intent-framework-handle-status-and-errors

---


## Core Patterns

Prefer data-first rendering when stale data is useful. A failed background refetch can produce `isError` while `data` is still available.

```tsx
const todos = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })

if (todos.data)
  return <TodoList todos={todos.data} isRefreshing={todos.isFetching} />
if (todos.isPending) return <Spinner />
if (todos.isError) return <ErrorMessage error={todos.error} />
return null
```

Use `throwOnError` when render-time Error Boundaries should own the fallback:

```tsx
useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  throwOnError: (error) => error.status >= 500,
})
```

Use global cache callbacks for cross-cutting notifications:

```ts
import { QueryCache, QueryClient } from '@tanstack/react-query'

const queryClient = new QueryClient({
  queryCache: new QueryCache({
    onError: (error, query) => {
      if (query.state.data !== undefined) showToast(error.message)
    },
  }),
})
```

## Common Mistakes

### HIGH Hiding stale data on background error

Wrong:

```tsx
if (query.isError) return <ErrorMessage error={query.error} />
if (query.data) return <Todos todos={query.data} />
```

Correct:

```tsx
if (query.data)
  return (
    <Todos todos={query.data} staleError={query.isError ? query.error : null} />
  )
if (query.isError) return <ErrorMessage error={query.error} />
```

Background refetch failures should not necessarily erase already-rendered data.

Source: https://tkdodo.eu/blog/status-checks-in-react-query

### HIGH Sending validation errors to a global boundary

Wrong:

```ts
useMutation({ mutationFn: submitForm, throwOnError: true })
```

Correct:

```ts
useMutation({
  mutationFn: submitForm,
  throwOnError: (error) => error.status >= 500,
})
```

Handle expected 4xx validation errors near the form. Send unexpected server failures to the boundary.

Source: https://tkdodo.eu/blog/react-query-error-handling

### MEDIUM Duplicating toast notifications per observer

Wrong:

```ts
useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  onError: toastError,
})
```

Correct:

```ts
new QueryClient({
  queryCache: new QueryCache({
    onError: (error, query) => {
      if (query.state.data !== undefined) toastError(error)
    },
  }),
})
```

Observer-level callbacks can duplicate notifications across components. Use cache-level callbacks for global side effects.

Source: https://tkdodo.eu/blog/react-query-error-handling

