15 KiB
DevDash - Super Hard Debug Challenge (16-18 Errors)
Challenge Overview
This is the super hard tier debug challenge with 16-18 intentional errors distributed across 6 categories. Students must identify and fix all errors to make the project run successfully.
CATEGORY 1: BLOCKING ERRORS (3 Errors)
Error 1: Missing Dependency - date-fns
File: src/lib/utils.ts
Issue: The code imports format from date-fns:
import { format } from "date-fns";
But date-fns is NOT listed in package.json.
Symptom: Runtime error: "Cannot find module 'date-fns'"
Fix: Add to package.json dependencies:
"dependencies": {
"date-fns": "^2.30.0"
}
Error 2: Wrong Import Path - next/navigations (with 's')
File: src/components/Header.tsx
Issue:
import { usePathname } from "next/navigations"; // WRONG - has 's'
Should be:
import { usePathname } from "next/navigation"; // CORRECT
Symptom: Module not found error at build time
Fix: Remove the 's' from the import path.
Error 3: Circular Dependency Crash
Files: src/lib/types.ts and src/lib/utils.ts
Issue:
In src/lib/utils.ts:
import { formatDate } from "./utils"; // Value import, not type
In src/lib/types.ts:
import { formatDate } from "./utils";
export function createPost(data: Omit<Post, "formattedDate">): Post {
return { ...data, formattedDate: formatDate(data.date) }; // formatDate is undefined!
}
Symptom: TypeError: formatDate is not a function at runtime
Fix: Use import type for types to avoid the circular dependency:
In src/lib/utils.ts:
import type { Post } from "./types"; // Change to type import
Alternatively, restructure to avoid circular imports altogether.
CATEGORY 2: NEXT.JS SPECIFIC ERRORS (4 Errors)
Error 4: Missing "use client" Directive
File: src/components/ThemeToggle.tsx
Issue: The component uses useState (a client-side hook) but lacks "use client" at the top.
// MISSING "use client" at the top!
import { useState } from 'react';
export function ThemeToggle() {
const [isHovered, setIsHovered] = useState(false);
// ...
}
Symptom: Next.js error: "You're importing a component that needs useState. It only works in Client Components."
Fix: Add at the very top of the file:
"use client";
import { useState } from 'react';
Error 5: Hooks in Server Component
File: src/app/dashboard/page.tsx
Issue: The page uses useState and useEffect directly:
// MISSING "use client" at the top!
import { useState, useEffect } from 'react';
export default function DashboardPage() {
const [isLoading, setIsLoading] = useState(false);
// ...
}
Symptom: Hydration error or "You're importing a component that needs useState"
Fix: Add "use client" directive at the top:
"use client";
import { useState, useEffect } from 'react';
Error 6: Wrong Middleware Matcher Pattern
File: middleware.ts
Issue:
export const config = {
matcher: ['/dashboard/:path'], // WRONG - missing asterisk
};
This matches /dashboard/:path but NOT /dashboard/page/subpage. The sub-routes won't be protected.
Also, the middleware looks for 'auth-token' cookie but the app doesn't set one:
const authToken = request.cookies.get('auth-token')?.value;
Symptom: Sub-routes of dashboard bypass middleware; authentication doesn't work
Fix:
export const config = {
matcher: ['/dashboard/:path*'], // Add asterisk for all sub-routes
};
And update cookie name to match what's actually used or create a mock auth mechanism.
Error 7: metadata Export in Client Component
File: src/app/blog/[slug]/page.tsx
Issue:
'use client'; // This is a CLIENT component
export const metadata = { // Can't export metadata from client!
title: 'Blog Post',
description: 'Read the full article',
};
import { useParams } from 'next/navigation';
Symptom: Build error: "Metadata exports must be in a Server Component"
Fix (Option 1): Remove 'use client' and use function parameters instead of useParams():
// Remove "use client"
import { generateMetadata } from 'next';
import type { Metadata } from 'next';
export async function generateMetadata({ params }): Promise<Metadata> {
const post = getPostBySlug(params.slug);
return {
title: post?.title || 'Blog Post',
description: post?.content.substring(0, 100) || '',
};
}
export default function BlogPostPage({ params }: { params: { slug: string } }) {
const post = getPostBySlug(params.slug);
// ...
}
Fix (Option 2): Keep as client component and remove metadata export:
'use client';
// Remove metadata export
import { useParams } from 'next/navigation';
// ... rest of component
CATEGORY 3: LOGIC ERRORS (3 Errors)
Error 8: Wrong Filter Condition
File: src/data/posts.ts
Issue:
export function getPublishedPosts(): Post[] {
return posts.filter(p => p.draft); // WRONG - returns DRAFTS!
}
Should check for !p.draft (NOT drafted):
export function getPublishedPosts(): Post[] {
return posts.filter(p => !p.draft); // CORRECT
}
Symptom: Blog page shows only draft posts (only 1 post visible instead of 2 published ones)
Fix: Change condition to !p.draft.
Error 9: Stale Closure in Event Handler
File: src/components/Testimonials.tsx
Issue:
useEffect(() => {
const timer = setInterval(() => {
setCurrentIndex(currentIndex + 1); // STALE CLOSURE!
}, 4000);
return () => clearInterval(timer);
}, []); // Empty dependency array captures initial value
The currentIndex is captured from the initial render (0). The interval always increments from 0 to 1, causing the carousel to jump back repeatedly.
Symptom: Testimonial carousel doesn't advance smoothly; always jumps to position 1
Fix: Use the functional update form of setState:
useEffect(() => {
const timer = setInterval(() => {
setCurrentIndex(prev => (prev + 1) % testimonials.length); // Use prev!
}, 4000);
return () => clearInterval(timer);
}, []);
Error 10: Using Index as Key
File: src/components/Features.tsx
Issue:
{displayedFeatures.map((feature, index) => (
<div key={index}> // WRONG - using index as key
{/* ... */}
</div>
))}
Using index as key is problematic if the list reorders or filters.
Symptom: Visual glitches when filtering features; component state gets mixed up
Fix: Use unique identifier:
{displayedFeatures.map((feature) => (
<div key={feature.id}> // Use feature.id
{/* ... */}
</div>
))}
CATEGORY 4: TYPESCRIPT ERRORS (2 Errors)
Error 11: Wrong API Response Type
File: src/app/api/stats/route.ts and src/components/StatsGrid.tsx
Issue:
API returns wrapped response:
// src/app/api/stats/route.ts
return NextResponse.json({ data: stats }); // Wrapped in { data: ... }
But component expects unwrapped array:
// src/components/StatsGrid.tsx
const data = await response.json();
setStats(data); // Expects data to be array, but gets { data: [...] }
Later:
{stats.map((stat, index) => ( // stats is an object, not array!
Symptom: TypeError: stats.map is not a function
Fix - Option 1: Unwrap in component:
const data = await response.json();
setStats(data.data); // Extract the array
Fix - Option 2: Change API response:
return NextResponse.json(stats); // Return array directly
Error 12: Missing Optional Chaining
File: src/components/UserProfile.tsx
Issue:
{user.profile.avatar} // profile could be undefined!
The API might return a user without a profile object:
const user: User = {
id: '1',
name: 'John',
email: 'john@example.com',
// profile is undefined!
};
Symptom: TypeError: Cannot read property 'avatar' of undefined
Fix: Use optional chaining:
{user.profile?.avatar} // Safe access
Or add a null check:
{user.profile && user.profile.avatar}
CATEGORY 5: REACT PATTERN ERRORS (3 Errors)
Error 13: Missing useEffect Cleanup
File: src/app/dashboard/page.tsx
Issue:
useEffect(() => {
window.addEventListener('resize', handleResize);
// Missing cleanup!
// Should have: return () => window.removeEventListener('resize', handleResize);
}, []);
Symptom: Memory leak; listeners accumulate when component remounts; "Can't perform a React state update on an unmounted component" warnings
Fix: Add cleanup function:
useEffect(() => {
function handleResize() {
setIsLoading(window.innerWidth < 768);
}
window.addEventListener('resize', handleResize);
// Add cleanup
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
Error 14: Incorrect Context Provider Wrapping
File: src/app/layout.tsx
Issue:
<body>
<Header /> {/* Header tries to use theme context but provider hasn't wrapped it yet! */}
<ThemeProvider>
<main>
{children}
</main>
<Footer />
</ThemeProvider>
</body>
The Header component is rendered BEFORE the ThemeProvider, so it can't access the theme context.
Symptom: Error in Header when trying to use useTheme(): "useTheme must be used within ThemeProvider"
Fix: Move provider to wrap everything:
<body>
<ThemeProvider>
<Header />
<main>
{children}
</main>
<Footer />
</ThemeProvider>
</body>
Error 15: Prop Drilling Mistake - Wrong Prop Name
File: src/app/blog/page.tsx and src/components/BlogCard.tsx
Issue:
BlogCard expects post:
// src/components/BlogCard.tsx
export function BlogCard({ post }: { post: Post }) {
return (
<article>
<h3>{post?.title || 'Untitled'}</h3>
{/* ... */}
</article>
);
}
But blog page passes blogPost:
// src/app/blog/page.tsx
{posts.map((post) => (
<BlogCard key={post.slug} blogPost={post} /> // WRONG prop name!
))}
Symptom: BlogCard displays "Untitled" and "Date unknown"; content is empty
Fix: Use correct prop name:
{posts.map((post) => (
<BlogCard key={post.slug} post={post} /> // Correct
))}
CATEGORY 6: STYLING ERRORS (3 Errors)
Error 16: Custom CSS Classes Instead of Tailwind
File: src/app/globals.css
Issue: The stylesheet defines custom classes:
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
.card {
background-color: white;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: 1.5rem;
}
.btn-primary {
background-color: #3b82f6;
color: white;
/* ... more styles ... */
}
In a Tailwind project, these should be Tailwind classes, not custom CSS.
Symptom: Custom classes work but don't align with Tailwind approach; styling is scattered between CSS and inline styles
Fix: Replace with Tailwind classes or @apply directives:
@layer components {
.container {
@apply max-w-5xl mx-auto px-4;
}
.card {
@apply bg-white rounded-lg shadow p-6;
}
.btn-primary {
@apply bg-blue-500 text-white px-6 py-3 rounded transition-colors hover:bg-blue-600;
}
}
Error 17-18: Inline Styles Instead of Tailwind Classes
Files: Multiple components use inline style={{}} instead of Tailwind:
src/components/Header.tsx- All styling is inlinesrc/components/Hero.tsx- All styling is inlinesrc/components/Features.tsx- All styling is inlinesrc/components/Testimonials.tsx- All styling is inlinesrc/components/StatsGrid.tsx- All styling is inlinesrc/components/BlogCard.tsx- All styling is inlinesrc/components/UserProfile.tsx- All styling is inline- And more...
Example Issue:
<header style={{
backgroundColor: '#ffffff',
borderBottom: '1px solid #e5e7eb',
padding: '1rem 0'
}}>
{/* ... */}
</header>
Should be:
<header className="bg-white border-b border-gray-200 py-4">
{/* ... */}
</header>
Symptom: Project uses Tailwind but styling isn't using Tailwind; inconsistent; not maintainable
Fix: Convert all inline styles to Tailwind classes. Example conversions:
backgroundColor: '#ffffff' → bg-white
borderBottom: '1px solid #e5e7eb' → border-b border-gray-200
padding: '1rem 0' → py-4
fontSize: '1.5rem' → text-2xl
fontWeight: 'bold' → font-bold
display: 'flex' → flex
gap: '1rem' → gap-4
justifyContent: 'center' → justify-center
alignItems: 'center' → items-center
Summary Table
| # | Category | Error | File | Severity |
|---|---|---|---|---|
| 1 | Blocking | Missing date-fns |
lib/utils.ts |
CRITICAL |
| 2 | Blocking | Wrong import next/navigations |
components/Header.tsx |
CRITICAL |
| 3 | Blocking | Circular dependency | lib/types.ts, lib/utils.ts |
CRITICAL |
| 4 | Next.js | Missing "use client" | components/ThemeToggle.tsx |
CRITICAL |
| 5 | Next.js | Hooks in server component | app/dashboard/page.tsx |
CRITICAL |
| 6 | Next.js | Wrong matcher pattern | middleware.ts |
HIGH |
| 7 | Next.js | Metadata in client component | app/blog/[slug]/page.tsx |
CRITICAL |
| 8 | Logic | Wrong filter condition | data/posts.ts |
MEDIUM |
| 9 | Logic | Stale closure | components/Testimonials.tsx |
MEDIUM |
| 10 | Logic | Index as key | components/Features.tsx |
MEDIUM |
| 11 | TypeScript | API response type mismatch | api/stats/route.ts, components/StatsGrid.tsx |
HIGH |
| 12 | TypeScript | Missing optional chaining | components/UserProfile.tsx |
MEDIUM |
| 13 | React | Missing useEffect cleanup | app/dashboard/page.tsx |
HIGH |
| 14 | React | Wrong provider wrapping | app/layout.tsx |
CRITICAL |
| 15 | React | Wrong prop name | app/blog/page.tsx, components/BlogCard.tsx |
MEDIUM |
| 16 | Styling | Custom CSS classes | app/globals.css |
LOW |
| 17-18 | Styling | Inline styles (8+ components) | Multiple components | LOW |
Debugging Strategy
- Start with blocking errors (1-3) - These prevent the app from running at all
- Fix Next.js errors (4-7) - These cause build-time failures
- Address logic errors (8-10) - These cause runtime misbehavior
- Resolve TypeScript errors (11-12) - These break specific features
- Fix React patterns (13-15) - These cause memory leaks and state issues
- Clean up styling (16-18) - These improve code quality and maintainability
Testing Checklist
After fixing all errors:
- App builds without errors:
npm run build - Dev server runs:
npm run dev - Homepage loads with Hero, Features, Testimonials
- All navigation links work
- Blog page shows published posts (2 posts, not drafts)
- Blog post pages load correctly
- Dashboard page loads with stats and user profile
- Theme toggle works (if fixed)
- Carousel auto-advances smoothly
- No console errors
- No memory leaks in browser dev tools