useLoaderData undefined error with Sanity query in Remix loader
This is a classic Remix loader issue where useLoaderData() returns undefined. Since you mentioned the same code works on another page, here are the most likely causes:
1. Loader Not Being Called (Most Common)
The most common reason is that your route file isn't properly exporting the loader or the file naming doesn't match Remix's routing conventions. Check:
- Is your file in the
app/routes/directory? - Is the loader export actually being recognized? Try adding a console.log at the very top of your loader to verify it's running:
export async function loader() {
console.log("LOADER EXECUTING"); // Check server logs
const posts = await getClient().fetch(/* ... */);
console.log("Posts count:", posts?.length);
return { posts };
}If you don't see "LOADER EXECUTING" in your server console when you visit the page, the loader isn't running at all.
2. Client-Side Navigation Issue
If you're navigating to this page from another page, Remix might be trying to call the loader but getting an error that's swallowed. Add error handling:
export async function loader() {
try {
const posts = await getClient().fetch(
`*[_type == "post"]{
_id,
title,
slug,
author,
"authorName": author->name,
"authorImage": author->image,
mainImage,
publishedAt,
categories,
excerpt,
myTags,
featuredPost,
"categoryName": *[_type == 'category' && _id in ^.categories[]._ref]{title, slug},
} | order(publishedAt desc)`
);
return { posts: posts || [] };
} catch (error) {
console.error("Sanity fetch error:", error);
throw new Response("Failed to load posts", { status: 500 });
}
}3. Sanity Client Configuration
Since it works elsewhere, this is less likely, but verify your getClient() function returns a properly configured client:
import { createClient } from "@sanity/client";
export function getClient() {
return createClient({
projectId: process.env.SANITY_PROJECT_ID, // or your hardcoded ID
dataset: process.env.SANITY_DATASET || "production",
apiVersion: "2024-01-01",
useCdn: false, // Important for loaders
});
}4. Defensive Component Code
As a quick fix while debugging, make your component more defensive:
export default function LatestBlogPosts() {
const data = useLoaderData();
const posts = data?.posts || [];
if (!posts || posts.length === 0) {
return <div>No posts found</div>;
}
return (
<section className="">
{/* your existing JSX */}
</section>
);
}5. Check for TypeScript Errors
If you're using TypeScript, make sure there are no type errors preventing the loader from compiling. Run npm run typecheck to verify.
Debugging Steps
- Check your server console logs (not browser console) when you load the page
- Verify the route file is in the correct location and named correctly
- Try hard-refreshing the page (Ctrl+Shift+R) instead of navigating to it
- Check if you have an
ErrorBoundaryexport in the same file that might be catching errors silently
The fact that identical code works on another page strongly suggests either a route configuration issue or the loader isn't being executed at all on this specific route. The console.log approach will quickly tell you which it is.
Show original thread16 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.