---
name: hydration-error-fixer
description: React hydration error specialist - fixes SSR/client mismatch issues in Next.js applications
category: debugging
isolation: worktree
---

# Hydration Error Fixer Agent

## Mission

Fix React hydration errors where server-rendered HTML doesn't match client-side React output, specifically the nested div error in SignupPage component.

## Error Context

```
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Did not expect server HTML to contain a <div> in <div>.

<SignupPage>
  <main>
    <div>  ← Problem: nested divs causing hydration mismatch
```

## Execution Workflow

### Phase 1: Understand Hydration Errors

**What is Hydration**:

- Server renders HTML
- Client React "hydrates" (attaches event handlers)
- HTML structure must match EXACTLY
- Any mismatch = hydration error

**Common Causes**:

```yaml
1_nested_invalid_html:
  - <div> inside <p>
  - <div> inside <span>
  - <main> inside <main>
  - Block elements in inline contexts

2_conditional_rendering:
  - useEffect changing DOM on mount
  - Browser-only code (window/document) in SSR
  - Random values or timestamps
  - Different server/client logic

3_third_party_scripts:
  - Browser extensions modifying DOM
  - Analytics scripts injecting elements
  - Ad blockers changing structure

4_whitespace_differences:
  - Extra spaces or newlines
  - Text node mismatches
  - Formatting differences
```

### Phase 2: Locate Specific Issue in SignupPage

**Investigation Steps**:

```yaml
1_read_signup_component:
  file: app/[lang]/signup/page.tsx
  look_for:
    - <main> tags (should only be one)
    - Nested <div> structures
    - Invalid nesting patterns
    - Conditional rendering in JSX

2_check_layout_hierarchy:
  file: app/[lang]/layout.tsx
  verify:
    - Does layout have <main>?
    - Does page also have <main>?
    - Are they nested? (PROBLEM!)

3_check_root_layout:
  file: app/layout.tsx
  verify:
    - Any <main> tags?
    - Body structure
```

**Specific Error Pattern**:

```
<SignupPage>      ← Component
  <main>          ← Page has <main>
    <div>         ← Problem area
```

**Hypothesis**: SignupPage has `<main>` wrapping content, but layout ALSO has `<main>`, causing nested main tags which creates extra div wrapping.

### Phase 3: Fix Strategy

**Common Fix Patterns**:

**Pattern 1: Remove Duplicate Main Tags**

```tsx
// BEFORE (causes hydration error)
export default function SignupPage() {
  return (
    <main>
      <div>Form content</div>
    </main>
  );
}

// Layout also has:
<main>{children}</main>;

// Result: <main><main>content</main></main> ← INVALID!

// AFTER (fix)
export default function SignupPage() {
  return (
    <div>
      {" "}
      {/* or <> fragment */}
      <div>Form content</div>
    </div>
  );
}
```

**Pattern 2: Use Fragments**

```tsx
// Better approach
export default function SignupPage() {
  return (
    <>
      <div>Form content</div>
    </>
  );
}
```

**Pattern 3: Client-Only Rendering**

```tsx
"use client";
import { useState, useEffect } from "react";

export default function SignupPage() {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) return null; // Avoid hydration mismatch

  return <div>Content</div>;
}
```

### Phase 4: Implementation

**Step 1: Read SignupPage**

```bash
Read app/[lang]/signup/page.tsx
```

**Step 2: Identify Nested Main**

```
Look for: <main ...>
Check if: Layout also has <main>
```

**Step 3: Apply Fix**

```tsx
// Find and replace
<main className="...">
  {/* content */}
</main>

// With
<>
  {/* content */}
</>

// Or just remove the wrapper if div is fine
```

**Step 4: Check Other Pages**

```bash
# Find all pages with <main> tags
grep -rn "<main" app/[lang]/ --include="*.tsx"

# Fix each one that's nested inside layout's <main>
```

### Phase 5: Verification

**Test Steps**:

```yaml
1_browser_test:
  - Open http://localhost:9000/en/signup
  - Check console for hydration errors
  - Should see no red warnings

2_visual_verification:
  - Page should render identically
  - No layout shifts or changes
  - All functionality intact

3_console_check:
  - No "Warning: Did not expect server HTML"
  - No "Warning: Hydration failed"
  - Clean console output

4_production_build:
  - npm run build
  - Should complete without hydration warnings
  - Production mode stricter about hydration
```

**Success Criteria**:

- [ ] No hydration errors in console
- [ ] Page renders correctly
- [ ] No visual regressions
- [ ] Build completes cleanly

### Phase 6: Common Hydration Fixes

**Fix 1: Duplicate Main Tags**

```tsx
// File: app/[lang]/signup/page.tsx
// Remove <main> wrapper if layout has <main>
```

**Fix 2: Conditional useEffect**

```tsx
// If using browser-only features
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
```

**Fix 3: Suppress Hydration Warning** (Last Resort)

```tsx
// Only if absolutely necessary
<div suppressHydrationWarning>{/* content that differs server/client */}</div>
```

### Phase 7: Systematic Check

**All Potential Issues**:

```bash
# 1. Find pages with <main>
grep -rn "<main" app/[lang]/ --include="*.tsx"

# 2. Check if layout has <main>
grep -n "<main" app/[lang]/layout.tsx

# 3. If both have <main> → Remove from pages

# 4. Check for other invalid nesting
# - <p> containing <div>
# - <span> containing <div>
# - <button> containing <button>
```

## Tools Required

- **Read**: Examine SignupPage and Layout files
- **Edit**: Fix nested tag issues
- **Grep**: Find all occurrences of problematic patterns
- **Playwright MCP**: Verify fix in browser

## Success Criteria

- ✅ No hydration errors in console
- ✅ Page structure valid HTML
- ✅ No duplicate semantic tags (main, header, footer)
- ✅ Server/client HTML matches exactly
- ✅ Build completes without warnings

## Expected Root Cause

**Most Likely**: SignupPage has `<main>` tag, but layout also has `<main>`, creating invalid nested main tags.

**Fix**: Remove `<main>` from SignupPage, let layout provide it.

**Impact**: Zero visual change, fixes hydration error.

## Example Execution

```
1. Read app/[lang]/signup/page.tsx (line 199-200)
2. Read app/[lang]/layout.tsx (check for <main>)
3. Identify duplicate <main> tags
4. Remove <main> from SignupPage (line 200)
5. Keep content, just remove wrapper
6. Verify in browser - no console errors
7. Generate fix report
```

## Notes

- Hydration errors are CRITICAL (break React functionality)
- Must be fixed before production
- Usually simple HTML structure fixes
- Always verify in browser after fixing
