๐ŸŒ Detecting your locationโ€ฆ
๐Ÿ“ข Advertisement โ€” Configure AdSense in Appearance โ†’ Customize โ†’ AdSense Settings

How to Fix 413 Request Entity Too Large Error in Nginx and Node.js

โฑ๏ธ4 min read  ยท  815 words

The error 413 Request Entity Too Large means the request body (usually a file upload or large JSON payload) exceeds the size limit your server allows. It often appears only in production because of nginx defaults. Here’s how to fix it at every layer.

What Causes This Error

Multiple layers can reject a large request:

  • Nginx (reverse proxy) has a default 1MB body limit
  • Express/Node.js body parser has its own limit (default ~100KB)
  • Upload middleware (multer) has configurable file size limits

The request must pass ALL layers โ€” fixing only one may not resolve it.

Fix 1: Nginx client_max_body_size

# nginx is the most common culprit โ€” default is 1MB

# In your server or location block:
server {
    # Allow up to 50MB request bodies
    client_max_body_size 50M;

    location /api/upload {
        client_max_body_size 100M;   # larger for upload endpoints
        proxy_pass http://localhost:3000;
    }
}

# Or globally in http block (/etc/nginx/nginx.conf):
http {
    client_max_body_size 50M;
}

# Reload nginx after changing
sudo nginx -t && sudo systemctl reload nginx

Fix 2: Express Body Parser Limit

const express = require('express');
const app = express();

// ๐Ÿ› Default limit is ~100KB โ€” large JSON fails
app.use(express.json());

// โœ… Increase the limit
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));

// For specific routes only:
app.post('/api/large', express.json({ limit: '100mb' }), handler);

Fix 3: Multer File Upload Limits

const multer = require('multer');

// Configure size limits for file uploads
const upload = multer({
  storage: multer.diskStorage({ /* ... */ }),
  limits: {
    fileSize: 50 * 1024 * 1024,   // 50MB per file
    files: 5,                      // max 5 files
  },
});

app.post('/upload', upload.single('file'), (req, res) => {
  res.json({ filename: req.file.filename });
});

// Handle multer's own limit error gracefully
app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError && err.code === 'LIMIT_FILE_SIZE') {
    return res.status(413).json({ error: 'File too large (max 50MB)' });
  }
  next(err);
});

All Three Layers Together

For a 50MB upload to succeed, all limits must allow it:

# 1. nginx (if used as reverse proxy)
client_max_body_size 50M;

# 2. Express body parser (for JSON/form data)
app.use(express.json({ limit: '50mb' }));

# 3. Multer (for multipart file uploads)
limits: { fileSize: 50 * 1024 * 1024 }

# The SMALLEST limit wins โ€” the request fails at the first layer that rejects it

Fix for Other Servers

# Apache โ€” in .htaccess or config
LimitRequestBody 52428800   # 50MB in bytes

# Cloudflare โ€” free plan limits uploads to 100MB
# (upgrade or upload directly to storage for larger files)

# Next.js API routes โ€” configure the body size limit
export const config = {
  api: {
    bodyParser: { sizeLimit: '50mb' },
  },
};

Better Approach: Upload Directly to Object Storage

For large files, don’t route them through your app server at all โ€” use presigned URLs to upload directly to S3/cloud storage:

// Backend generates a presigned upload URL
app.post('/api/presign', async (req, res) => {
  const url = await s3.getSignedUrl('putObject', {
    Bucket: 'my-bucket',
    Key: `uploads/${req.body.filename}`,
    Expires: 300,
  });
  res.json({ uploadUrl: url });
});

// Frontend uploads directly to S3 โ€” bypasses your server's limits entirely
const { uploadUrl } = await fetch('/api/presign', { /* ... */ }).then(r => r.json());
await fetch(uploadUrl, { method: 'PUT', body: file });
// No 413 โ€” the file never passes through your app server

Frequently Asked Questions

Q: Why does it work locally but fail in production?
A: Production usually has nginx (or another reverse proxy) in front of your app with a default 1MB body limit. Locally you hit your app directly without that proxy. Increase client_max_body_size in nginx.

Q: I increased Express’s limit but still get 413. Why?
A: nginx is rejecting the request before it reaches Express. The reverse proxy’s client_max_body_size must also be increased. Fix all layers โ€” the smallest limit wins.

Q: What’s a reasonable body size limit?
A: Set it as low as your use case allows โ€” large limits increase abuse/DoS risk. For JSON APIs, a few MB is plenty. For file uploads, size to your largest legitimate file, or better, upload directly to object storage.

Q: Should large files go through my app server at all?
A: Ideally no โ€” use presigned URLs to upload directly to S3/cloud storage. This avoids body size limits entirely, reduces server load, and scales better. Route only metadata through your app.

Q: How do I return a friendly error instead of a raw 413?
A: Catch the limit error in your middleware (multer’s LIMIT_FILE_SIZE, or a body-parser error) and return a clear JSON message. Also validate file size on the frontend before uploading to give immediate feedback.

Conclusion

“413 Request Entity Too Large” means a request body exceeds a server limit โ€” and it often has multiple layers. The fix: increase client_max_body_size in nginx, raise Express’s body parser limit, and configure multer’s fileSize โ€” all three must allow the size since the smallest limit wins. It typically appears in production because of nginx’s 1MB default. For large files, the best solution is uploading directly to object storage with presigned URLs, bypassing your app server’s limits entirely and scaling better.

โœ๏ธ Leave a Comment

Your email address will not be published. Required fields are marked *