-
Notifications
You must be signed in to change notification settings - Fork 3
Fix repo not found crash and improve 404 page #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add custom not-found pages to handle cases where users navigate to repos that don't exist. The repo 404 shows a link to check GitHub directly.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
notFound() doesn't work correctly inside "use cache" functions in Next.js 16. Restructured all pages to check for existence before the cache boundary. Also added custom not-found pages for posts and categories.
| // Post existence already verified before cache boundary | ||
| const { category, gitContexts, ...post } = postWithCategory! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Post existence already verified before cache boundary | |
| const { category, gitContexts, ...post } = postWithCategory! | |
| // Defensive check: post should exist (verified before cache boundary), | |
| // but we add this check to handle race conditions or data inconsistencies. | |
| // If the post is not found, we notFound() even though we're in a cached function, | |
| // as this is a data integrity issue that should be handled gracefully. | |
| if (!postWithCategory) { | |
| notFound() | |
| } | |
| const { category, gitContexts, ...post } = postWithCategory |
Non-null assertion on postWithCategory! without null check could crash with TypeError if post is deleted between queries or data becomes inconsistent
View Details
📝 Patch Details
diff --git a/app/[owner]/[repo]/[postNumber]/page.tsx b/app/[owner]/[repo]/[postNumber]/page.tsx
index 8450d34..bd795b2 100644
--- a/app/[owner]/[repo]/[postNumber]/page.tsx
+++ b/app/[owner]/[repo]/[postNumber]/page.tsx
@@ -242,8 +242,15 @@ async function PostPageContent({
.where(and(eq(categories.owner, owner), eq(categories.repo, repo))),
])
- // Post existence already verified before cache boundary
- const { category, gitContexts, ...post } = postWithCategory!
+ // Defensive check: post should exist (verified before cache boundary),
+ // but we add this check to handle race conditions or data inconsistencies.
+ // If the post is not found, we notFound() even though we're in a cached function,
+ // as this is a data integrity issue that should be handled gracefully.
+ if (!postWithCategory) {
+ notFound()
+ }
+
+ const { category, gitContexts, ...post } = postWithCategory
const gitContext = gitContexts?.[0] ?? null
cacheTag(`post:${post.id}`)
Analysis
BUG ANALYSIS:
The code on line 245 uses a non-null assertion without a defensive null check:
const { category, gitContexts, ...post } = postWithCategory!This was changed from a previous version that had an explicit null check (if (!postWithCategory) { notFound() }). The developer's assumption is that because the post exists was verified in the PostPage function before the cache boundary, it will definitely exist in PostPageContent. However, this assumption breaks down for several reasons:
-
Race Condition Between Queries: The
PostPagefunction checks if the post exists usinggetPostByNumber(), but thenPostPageContentqueries the database again independently. Between these two queries, the post could be deleted from the database. -
Different Query Structures: The first check uses
getPostByNumber()(from lib/data/posts), while the second uses a direct Drizzle query with a LEFT JOIN. These queries could diverge if there's data inconsistency or timing issues. -
Unsafe Destructuring: If
postWithCategoryis undefined at runtime, TypeScript's non-null assertion doesn't prevent a crash. Instead, the destructuring will throw:TypeError: Cannot destructure property 'category' of 'undefined' (reading 'category'). This is worse than a graceful 404. -
Edge Cases: While race conditions are rare, they're possible especially in high-concurrency scenarios or if the post is deleted between the initial check and the cache query.
FIX EXPLANATION:
The fix restores the null check that was previously present:
if (!postWithCategory) {
notFound()
}
const { category, gitContexts, ...post } = postWithCategoryThis handles the edge case where the post becomes unavailable due to:
- Race conditions where post is deleted between queries
- Data consistency issues between the two query structures
- Any other unexpected conditions
By calling notFound(), users get a proper 404 page instead of a server error. The check also removes the type-unsafe non-null assertion, making the code more robust.
Add custom not-found pages to handle cases where users navigate to repos that don't exist. The repo 404 shows a link to check GitHub directly.