6.6 KiB
Top TanStack Query Errors & Solutions
Complete error reference with fixes
Error #1: Object Syntax Required
Error Message:
TypeError: useQuery is not a function
Property 'queryKey' does not exist on type...
Why: v5 removed function overloads, only object syntax works
Fix:
// ❌ v4 syntax
useQuery(['todos'], fetchTodos)
// ✅ v5 syntax
useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
Source: v5 Migration Guide
Error #2: Query Callbacks Not Working
Error Message:
Property 'onSuccess' does not exist on type 'UseQueryOptions'
Why:
onSuccess, onError, onSettled removed from queries (still work in mutations)
Fix:
// ❌ v4
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
onSuccess: (data) => console.log(data)
})
// ✅ v5 - Use useEffect
const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
useEffect(() => {
if (data) console.log(data)
}, [data])
Source: v5 Breaking Changes
Error #3: isLoading Always False
Error Message:
No error, but isLoading is false during initial fetch
Why:
v5 changed isLoading meaning: now isPending && isFetching
Fix:
// ❌ v4
const { isLoading } = useQuery(...)
if (isLoading) return <Loading />
// ✅ v5
const { isPending } = useQuery(...)
if (isPending) return <Loading />
Source: v5 Migration
Error #4: cacheTime Not Recognized
Error Message:
Property 'cacheTime' does not exist on type 'UseQueryOptions'
Why:
Renamed to gcTime (garbage collection time)
Fix:
// ❌ v4
cacheTime: 1000 * 60 * 60
// ✅ v5
gcTime: 1000 * 60 * 60
Source: v5 Migration
Error #5: useSuspenseQuery + enabled
Error Message:
Property 'enabled' does not exist on type 'UseSuspenseQueryOptions'
Why: Suspense guarantees data is available, can't conditionally disable
Fix:
// ❌ Wrong
useSuspenseQuery({
queryKey: ['todo', id],
queryFn: () => fetchTodo(id),
enabled: !!id,
})
// ✅ Correct: Conditional rendering
{id ? <TodoComponent id={id} /> : <div>No ID</div>}
Source: GitHub Discussion #6206
Error #6: initialPageParam Required
Error Message:
Property 'initialPageParam' is missing in type 'UseInfiniteQueryOptions'
Why:
v5 requires explicit initialPageParam for infinite queries
Fix:
// ❌ v4
useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam = 0 }) => fetchProjects(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor,
})
// ✅ v5
useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam }) => fetchProjects(pageParam),
initialPageParam: 0, // Required
getNextPageParam: (lastPage) => lastPage.nextCursor,
})
Source: v5 Migration
Error #7: keepPreviousData Not Working
Error Message:
Property 'keepPreviousData' does not exist on type 'UseQueryOptions'
Why:
Replaced with placeholderData function
Fix:
// ❌ v4
keepPreviousData: true
// ✅ v5
import { keepPreviousData } from '@tanstack/react-query'
placeholderData: keepPreviousData
Source: v5 Migration
Error #8: TypeScript Error Type
Error Message: Type errors when handling non-Error objects
Why:
v5 defaults to Error type instead of unknown
Fix:
// If throwing non-Error types, specify explicitly:
const { error } = useQuery<DataType, string>({
queryKey: ['data'],
queryFn: async () => {
if (fail) throw 'custom error string'
return data
},
})
// Better: Always throw Error objects
throw new Error('Custom error')
Source: v5 Migration
Error #9: Query Not Refetching
Symptoms: Data never updates even when stale
Why: Usually config issue - check staleTime, refetch options
Fix:
// Check these settings
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
staleTime: 0, // Data stale immediately
refetchOnWindowFocus: true,
refetchOnMount: true,
refetchOnReconnect: true,
})
// Or manually refetch
const { refetch } = useQuery(...)
refetch()
// Or invalidate
queryClient.invalidateQueries({ queryKey: ['todos'] })
Error #10: Mutations Not Invalidating
Symptoms: UI doesn't update after mutation
Why: Forgot to invalidate queries
Fix:
useMutation({
mutationFn: addTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] }) // ✅ Required
},
})
Error #11: Network Errors Not Caught
Symptoms: App crashes on network errors
Why: Not handling errors properly
Fix:
// Always handle errors
const { data, error, isError } = useQuery({
queryKey: ['todos'],
queryFn: async () => {
const response = await fetch('/api/todos')
if (!response.ok) {
throw new Error(`HTTP ${response.status}`) // ✅ Throw errors
}
return response.json()
},
})
if (isError) return <div>Error: {error.message}</div>
Error #12: Stale Closure in Callbacks
Symptoms: Mutation callbacks use old data
Why: Closure captures stale values
Fix:
// ❌ Stale closure
const [value, setValue] = useState(0)
useMutation({
onSuccess: () => {
console.log(value) // Stale!
},
})
// ✅ Use functional update
useMutation({
onSuccess: () => {
setValue(prev => prev + 1) // Fresh value
},
})
Quick Diagnosis Checklist
- Using v5 object syntax?
- Using
isPendinginstead ofisLoading? - Using
gcTimeinstead ofcacheTime? - No query callbacks (
onSuccess, etc.)? initialPageParampresent for infinite queries?- Throwing errors in queryFn?
- Invalidating queries after mutations?
- Check DevTools for query state