What Causes This Error?
This error occurs when your useAsyncData handler function returns something other than an object (like a primitive value, array, or undefined).
The Problem
<script setup>
// ❌ Wrong - returns a string
const { data } = await useAsyncData('user', () => {
return 'John' // Error: should return an object
})
// ❌ Wrong - returns undefined
const { data } = await useAsyncData('user', async () => {
const user = await fetchUser()
// Missing return statement!
})
// ❌ Wrong - returns an array directly
const { data } = await useAsyncData('users', () => {
return ['John', 'Jane'] // Arrays are technically objects but not recommended
})
</script>
The Fix
Return an Object
<script setup>
// ✅ Correct - return an object
const { data } = await useAsyncData('user', () => {
return { name: 'John' }
})
// ✅ Correct - wrap primitives in an object
const { data } = await useAsyncData('count', async () => {
const count = await fetchCount()
return { count }
})
// ✅ Correct - wrap arrays in an object
const { data } = await useAsyncData('users', async () => {
const users = await fetchUsers()
return { users }
})
</script>
Common Patterns
Fetching a Single Value
<script setup>
// ❌ Wrong
const { data } = await useAsyncData('title', () => $fetch('/api/title'))
// If API returns just a string, this fails
// ✅ Correct - wrap the response
const { data } = await useAsyncData('title', async () => {
const title = await $fetch('/api/title')
return { title }
})
// Access it
console.log(data.value?.title)
</script>
Fetching Multiple Values
<script setup>
// ✅ Correct - return object with multiple properties
const { data } = await useAsyncData('dashboard', async () => {
const [users, posts, stats] = await Promise.all([
$fetch('/api/users'),
$fetch('/api/posts'),
$fetch('/api/stats')
])
return { users, posts, stats }
})
// Access them
console.log(data.value?.users)
console.log(data.value?.posts)
console.log(data.value?.stats)
</script>
Using useFetch
Note: useFetch handles this automatically since API responses are typically objects:
<script setup>
// ✅ useFetch works because APIs usually return objects
const { data } = await useFetch('/api/user') // { name: 'John', email: '...' }
// If your API returns a primitive, use transform:
const { data } = await useFetch('/api/count', {
transform: (count) => ({ count })
})
</script>
With Transform
<script setup>
// ✅ Transform to ensure object structure
const { data } = await useAsyncData('users', () => $fetch('/api/users'), {
transform: (users) => ({
users,
total: users.length
})
})
</script>
Handling Different Response Types
API Returns Object (Good)
<script setup>
// API returns { name: 'John', email: 'john@example.com' }
const { data } = await useAsyncData('user', () => $fetch('/api/user'))
// ✅ Works fine
</script>
API Returns Array
<script setup>
// API returns ['item1', 'item2']
const { data } = await useAsyncData('items', async () => {
const items = await $fetch('/api/items')
return { items } // ✅ Wrap in object
})
// Access: data.value?.items
</script>
API Returns Primitive
<script setup>
// API returns 42
const { data } = await useAsyncData('count', async () => {
const count = await $fetch('/api/count')
return { count } // ✅ Wrap in object
})
// Access: data.value?.count
</script>
API Returns null
<script setup>
// API might return null
const { data } = await useAsyncData('user', async () => {
const user = await $fetch('/api/user')
return { user } // ✅ Wrap even if null
})
// Access: data.value?.user (will be null)
</script>
Async/Await Pitfalls
Missing Return
<script setup>
// ❌ Wrong - no return
const { data } = await useAsyncData('user', async () => {
const user = await $fetch('/api/user')
// Oops! No return statement
})
// ✅ Correct - return the data
const { data } = await useAsyncData('user', async () => {
const user = await $fetch('/api/user')
return { user }
})
</script>
Conditional Return
<script setup>
// ❌ Wrong - might return undefined
const { data } = await useAsyncData('user', async () => {
const user = await $fetch('/api/user')
if (user) {
return { user }
}
// Returns undefined if no user!
})
// ✅ Correct - always return an object
const { data } = await useAsyncData('user', async () => {
const user = await $fetch('/api/user')
return { user: user || null }
})
</script>
TypeScript Best Practices
<script setup lang="ts">
interface User {
id: number
name: string
}
interface UserData {
user: User | null
}
// ✅ Type-safe approach
const { data } = await useAsyncData<UserData>('user', async () => {
const user = await $fetch<User>('/api/user')
return { user }
})
// data.value?.user is typed as User | null
</script>
Destructuring in Template
<script setup>
const { data } = await useAsyncData('dashboard', async () => {
const [user, settings] = await Promise.all([
$fetch('/api/user'),
$fetch('/api/settings')
])
return { user, settings }
})
</script>
<template>
<div v-if="data">
<h1>{{ data.user?.name }}</h1>
<p>Theme: {{ data.settings?.theme }}</p>
</div>
</template>
Quick Checklist
- Handler function returns an object, not a primitive
- Arrays are wrapped in an object:
{ items: [...] } - Primitives are wrapped:
{ value: 123 } - Always have a return statement
- Conditional paths all return objects
- Use TypeScript for type safety