Nuxt Content not loading with NuxtLink

I am getting started with Nuxt content and have configured and index and slug page to display my blog directory. The problem I am running into is when clicking on the NuxtLink generated on the index page(ex /blog/hello), it goes to the appropriate link but doesn't display anything. If I remove the v-if from the slug, I get the following error via console
Invalid prop: type check failed for prop "value". Expected Object, got Null
Invalid prop: type check failed for prop "value". Expected Object, got Null
If I access the link directly the page renders as expected. This one has me a little perplexed. Any help is greatly appreciated. index.vue
<script setup lang="ts">
const { data: posts } = await useAsyncData("blog", () =>
queryCollection("blog").all()
);
</script>

<template>
<div>
<h1>Blogs:</h1>
<ul>
<li v-for="post in posts" :key="post.id">
{{ post.path }}
<NuxtLink :to="post.path">{{ post.title }}</NuxtLink>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
const { data: posts } = await useAsyncData("blog", () =>
queryCollection("blog").all()
);
</script>

<template>
<div>
<h1>Blogs:</h1>
<ul>
<li v-for="post in posts" :key="post.id">
{{ post.path }}
<NuxtLink :to="post.path">{{ post.title }}</NuxtLink>
</li>
</ul>
</div>
</template>
slug.vue
<script lang="ts" setup>
const route = useRoute();
const { data: blog } = await useAsyncData(route.path, () => {
return queryCollection("blog").path(route.path).first();
});
</script>

<template>
<!-- Render the blog post as Prose & Vue components -->
<ContentRenderer v-if="blog" :value="blog" />
</template>
<script lang="ts" setup>
const route = useRoute();
const { data: blog } = await useAsyncData(route.path, () => {
return queryCollection("blog").path(route.path).first();
});
</script>

<template>
<!-- Render the blog post as Prose & Vue components -->
<ContentRenderer v-if="blog" :value="blog" />
</template>
3 Replies
kapa.ai
kapa.ai4w ago
Hi @mast3rof0. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Your setup for listing blog posts and rendering individual posts with Nuxt Content is correct and matches the recommended approach in the documentation. The error you’re seeing:
Invalid prop: type check failed for prop "value". Expected Object, got Null
Invalid prop: type check failed for prop "value". Expected Object, got Null
happens because the <ContentRenderer> component expects a non-null object for its value prop, but sometimes blog is null or undefined when the component renders—especially during client-side navigation with <NuxtLink>. This is a common scenario when using async data fetching. Why does this happen? - On initial navigation, useAsyncData is still fetching the data, so blog is null. - If you remove the v-if="blog", you pass null to <ContentRenderer>, which causes the error. How to fix it: - Keep the v-if="blog" on <ContentRenderer> to ensure it only renders when data is available. - Optionally, add a fallback for loading and not found states. Example fix for slug.vue:
<script lang="ts" setup>
const route = useRoute();
const { data: blog, pending } = await useAsyncData(route.path, () => {
return queryCollection("blog").path(route.path).first();
});
</script>

<template>
<ContentRenderer v-if="blog" :value="blog" />
<div v-else-if="pending">Loading...</div>
<div v-else>Blog post not found.</div>
</template>
<script lang="ts" setup>
const route = useRoute();
const { data: blog, pending } = await useAsyncData(route.path, () => {
return queryCollection("blog").path(route.path).first();
});
</script>

<template>
<ContentRenderer v-if="blog" :value="blog" />
<div v-else-if="pending">Loading...</div>
<div v-else>Blog post not found.</div>
</template>
This approach is also shown in the official docs and ensures you never pass null to <ContentRenderer>, preventing the error and improving the user experience with loading and not found states Docs: ContentRenderer. Summary:
- Always guard <ContentRenderer> with v-if="blog" to avoid passing null. - Add loading and not found fallbacks for a better UX. This pattern is the recommended way to handle async content loading in Nuxt Content apps Docs: Render Content Docs: Implement Document Driven mode. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1369461878622916610> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
mast3rof0
mast3rof0OP4w ago
based on the feedback from kapa.ai, I added teh following to my slug
<template>
<ContentRenderer v-if="blog" :value="blog" />
<div v-else-if="pending">Loading...</div>
<div v-else>Blog post not found.</div>
</template>
<template>
<ContentRenderer v-if="blog" :value="blog" />
<div v-else-if="pending">Loading...</div>
<div v-else>Blog post not found.</div>
</template>
This resulted in teh page showing 'Blog post not found' when accessing from NuxtLink Good news / bad news. Good news is that the issue is resolved. The original problem I was having was on the Cloudflare distribution which. was using Nuxt 3.18. Recently they have updated to 4.0.3. After redeploying, everthing seems to be working as expected

Did you find this page helpful?