HTTP

Status Code

HTTP 404 Not Found: What It Means and How to Fix It

Learn what a 404 Not Found error means, why it happens, and how to fix it. Complete guide with examples for developers and users.

7 min read beginner Try in Playground

TL;DR: 404 Not Found means the server can’t find the resource. Check the URL for typos or see if the page was moved.

404 is the most recognized HTTP error code. It means the server understood your request but cannot find what you asked for. The address exists, but nobody is home.

What is a 404 Error?

When you request a URL, the server looks for that resource. If it doesn’t exist, the server returns a 404 status code:

GET /pages/nonexistent HTTP/1.1
Host: example.com
```text

Response:

```http
HTTP/1.1 404 Not Found
Content-Type: text/html

<!DOCTYPE html>
<html>
<head><title>404 Not Found</title></head>
<body>
  <h1>Page Not Found</h1>
  <p>The page you requested could not be found.</p>
</body>
</html>

Think of it like mailing a letter to an address that doesn’t exist—the postal service knows the street, but there’s no house at that number.

Common Causes

1. Typos in the URL

You typed:    https://example.com/abuot
Should be:    https://example.com/about
                                   ↑ typo

2. Deleted or Moved Content

Old URL:      https://blog.com/posts/old-article
Status:       Page was deleted or moved
Solution:     Should redirect to new location
<!-- Link points to non-existent page -->
<a href="/products/discontinued-item">Buy Now</a>
```text

### 4. Case Sensitivity

Some servers treat URLs as case-sensitive:

```text
/About    → 404 Not Found
/about    → 200 OK
```text

### 5. Missing File Extensions

```text
/page.html  → 200 OK
/page       → 404 Not Found (on some servers)
```text

### 6. Incorrect API Endpoints

```http
GET /api/v1/users/99999 HTTP/1.1

User ID 99999 doesn’t exist → 404

Example Responses

HTML Error Page

HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Content-Length: 1234

<!DOCTYPE html>
<html>
<head>
  <title>Page Not Found | Example.com</title>
</head>
<body>
  <h1>404 - Page Not Found</h1>
  <p>Sorry, we couldn't find that page.</p>
  <a href="/">Go to Homepage</a>
</body>
</html>
```text

### JSON API Response

```http
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {
    "code": "NOT_FOUND",
    "message": "The requested resource was not found",
    "details": {
      "resource": "User",
      "id": "99999"
    }
  }
}

Minimal Response

HTTP/1.1 404 Not Found
Content-Length: 0
```text

## How to Fix 404 Errors

### For Users

1. **Check the URL** - Look for typos
2. **Remove path segments** - Try `/products` instead of `/products/item/123`
3. **Use site search** - Find the content another way
4. **Check your bookmarks** - The page may have moved
5. **Try the homepage** - Navigate from there
6. **Use the Wayback Machine** - See archived versions at archive.org

### For Developers

#### 1. Implement Proper Redirects

```http
# Old URL → New URL
HTTP/1.1 301 Moved Permanently
Location: /new-page-url

2. Create a Helpful 404 Page

<!DOCTYPE html>
<html>
  <head>
    <title>Page Not Found</title>
  </head>
  <body>
    <h1>404 - Page Not Found</h1>
    <p>The page you're looking for doesn't exist.</p>

    <h2>What you can do:</h2>
    <ul>
      <li><a href="/">Go to Homepage</a></li>
      <li><a href="/search">Search our site</a></li>
      <li><a href="/sitemap">View Sitemap</a></li>
    </ul>

    <h2>Popular Pages:</h2>
    <ul>
      <li><a href="/products">Products</a></li>
      <li><a href="/about">About Us</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </body>
</html>
```javascript

#### 3. Log and Monitor 404s

```javascript
// Track 404 errors
app.use((req, res, next) => {
  res.status(404)

  // Log for analysis
  console.log(`404: ${req.method} ${req.url}`)

  // Send response
  res.render('404', { url: req.url })
})

4. Set Up Redirects for Moved Content

# Nginx redirect
location /old-page {
    return 301 /new-page;
}
```text

```apache
# Apache .htaccess
Redirect 301 /old-page /new-page

Production 404 Troubleshooting Checklist

Use this sequence when a route should exist but returns 404 in production.

1. Confirm Source of Truth

  1. Verify the route/file exists in the current release artifact
  2. Confirm the expected URL path and trailing-slash format
  3. Check case sensitivity (/Docs vs /docs)

2. Validate Framework Routing

  1. Ensure dynamic route params are generated (for static builds) or resolved at runtime
  2. Check rewrites/redirects do not shadow the intended route
  3. Confirm fallback/404 handling is not catching a valid path too early
  1. Crawl internal links for typos and outdated slugs
  2. Review sitemap entries for stale URLs
  3. Fix canonical/hreflang URLs that point to non-existent paths

4. Audit Cache Layers

  1. Browser cache: hard refresh and test in incognito
  2. CDN cache: purge affected URL patterns
  3. Reverse proxy/app cache: invalidate stale route manifests

5. Verify Edge and Origin Behavior

  1. Test the same URL from multiple regions/PoPs
  2. Compare CDN edge response vs origin response for the same request
  3. Check edge rules (workers, transforms, rewrites) for path mutations

6. Deploy Safety Checks

  1. Ensure atomic deploy of pages + assets + route manifests
  2. Keep backward-compatible redirects for renamed URLs
  3. Add synthetic checks for top pages immediately after deploy

7. Observe and Close the Loop

  1. Log structured 404 events with referrer, user-agent, and requested path
  2. Rank top 404 paths weekly and fix highest-impact issues first
  3. Revalidate in Search Console after fixes are live

404 vs Similar Status Codes

CodeNameMeaningUse Case
404Not FoundResource doesn’t existDefault for missing resources
410GonePermanently deletedTell search engines to remove
400Bad RequestInvalid request syntaxMalformed URL or parameters
403ForbiddenAccess deniedResource exists but no permission
401UnauthorizedAuth requiredNeed to log in first

When to Use 404 vs 410

# 404: Resource might exist later
GET /products/coming-soon → 404 Not Found

# 410: Resource is permanently gone
GET /products/discontinued → 410 Gone
```text

Use 410 when you want search engines to remove the URL from their index faster.

## API Design Best Practices

### Return Helpful Error Messages

```json
{
  "error": {
    "status": 404,
    "code": "USER_NOT_FOUND",
    "message": "No user found with ID 12345",
    "suggestion": "Check the user ID or list all users at GET /api/users"
  }
}

Be Consistent

// Always return the same error format
function notFound(resource, id) {
  return {
    error: {
      status: 404,
      code: `${resource.toUpperCase()}_NOT_FOUND`,
      message: `${resource} with ID ${id} not found`
    }
  }
}
```javascript

### Don't Leak Information

```json
// ❌ Bad: Reveals system details
{
  "error": "File /var/www/app/users/123.json not found"
}

// ✅ Good: Generic message
{
  "error": "User not found"
}

SEO Considerations

Soft 404s (Avoid These)

A “soft 404” returns 200 OK but shows “not found” content:

HTTP/1.1 200 OK  ← Wrong!

<h1>Page Not Found</h1>
```text

Search engines get confused. Always return proper 404 status codes.

### Redirect Deleted Content

```http
# Instead of 404 for deleted blog post
HTTP/1.1 301 Moved Permanently
Location: /blog/related-article

Monitor in Search Console

Google Search Console shows 404 errors that Googlebot encounters. Fix important ones by:

  1. Creating the missing page
  2. Redirecting to relevant content
  3. Removing broken links

JavaScript Handling

Fetch API

async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`)

  if (response.status === 404) {
    return null // User doesn't exist
  }

  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`)
  }

  return response.json()
}

// Usage
const user = await fetchUser(123)
if (!user) {
  showMessage('User not found')
}
```javascript

### React Error Handling

```jsx
function UserProfile({ userId }) {
  const [user, setUser] = useState(null)
  const [notFound, setNotFound] = useState(false)

  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then((res) => {
        if (res.status === 404) {
          setNotFound(true)
          return null
        }
        return res.json()
      })
      .then((data) => setUser(data))
  }, [userId])

  if (notFound) {
    return <div>User not found</div>
  }

  return user ? <div>{user.name}</div> : <div>Loading...</div>
}

Common Mistakes

❌ Returning 200 for Missing Resources

// Wrong
app.get('/users/:id', (req, res) => {
  const user = findUser(req.params.id)
  if (!user) {
    res.json({ error: 'Not found' }) // Still 200!
  }
})

// Correct
app.get('/users/:id', (req, res) => {
  const user = findUser(req.params.id)
  if (!user) {
    res.status(404).json({ error: 'Not found' })
  }
})
```text

### ❌ Using 404 for Authorization

```javascript
// Wrong: Hiding existence with 404
if (!user.canAccess(resource)) {
  return res.status(404).json({ error: 'Not found' })
}

// Correct: Use proper status code
if (!user.canAccess(resource)) {
  return res.status(403).json({ error: 'Forbidden' })
}

Try It Yourself

See a 404 response in our request builder:

  1. Select GET method
  2. Set path to /posts/99999 (non-existent ID)
  3. Click Send and observe the 404 response

In Practice

Express.js
// Return 404 for missing resources
app.get('/api/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id)
  if (!user) {
    return res.status(404).json({
      error: 'not_found',
      message: `User ${req.params.id} not found`
    })
  }
  res.json(user)
})

// Catch-all 404 handler (must be last)
app.use((req, res) => {
  res.status(404).json({ error: 'not_found', path: req.path })
})
Next.js App Router
// app/api/users/[id]/route.ts
import { notFound } from 'next/navigation'

export async function GET(
  _req: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.users.findById(params.id)
  if (!user) {
    // For API routes, return 404 response directly
    return new Response(
      JSON.stringify({ error: 'not_found' }),
      { status: 404, headers: { 'Content-Type': 'application/json' } }
    )
  }
  return Response.json(user)
}

// For page routes, call notFound() to render the not-found.tsx page
Django
from django.http import JsonResponse
from django.shortcuts import get_object_or_404

# Option 1: get_object_or_404 raises Http404 automatically
def user_detail(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    return JsonResponse(user.to_dict())

# Option 2: Manual 404 for APIs
def user_detail_api(request, user_id):
    try:
        user = User.objects.get(pk=user_id)
        return JsonResponse(user.to_dict())
    except User.DoesNotExist:
        return JsonResponse({'error': 'not_found'}, status=404)

Frequently Asked Questions

What does 404 Not Found mean?

A 404 error means the server cannot find the requested resource. The URL you requested does not exist on the server. This could be due to a typo, a deleted page, or a broken link.

How do I fix a 404 error?

Check the URL for typos, try removing parts of the URL to find a parent page, use the site search, or go to the homepage. If you are a developer, check your routing configuration and ensure the resource exists.

Is a 404 error my fault or the website fault?

It can be either. If you typed the URL manually, check for typos. If you clicked a link, the website has a broken link. If you used a bookmark, the page may have been moved or deleted.

What is the difference between 404 and 410?

404 means the resource was not found (might exist later). 410 Gone means the resource existed before but has been permanently deleted and will not return. Use 410 when you want search engines to remove the page from their index.

Can a 404 error hurt my SEO?

A few 404 errors are normal and do not hurt SEO. However, many 404 errors from broken internal links can harm your site. Search engines may see it as poor maintenance. Always redirect deleted pages to relevant content using 301 redirects.

Why do I see 404 errors in my browser console?

Browser console 404 errors usually mean your page is trying to load resources (images, scripts, stylesheets) that do not exist. Check the failed URL and ensure the file exists at that path.

Why does the page exist but users still get intermittent 404 errors?

Intermittent 404s are often caused by stale CDN cache, edge routing mismatch, or deploy race conditions where some edges still serve older routing tables. Purge cache, verify edge rules, and confirm all regions are on the same release.

Keep Learning