Express에서 ‘request entity too large’ 413 에러 해결

검증 환경

본 절은 원문 사례·문서에 등장한 버전/도구를 정리한 것이다. 별도 실험실 재현이 명시되지 않은 항목은 일반화하지 않는다.

항목본문·원문에서 확인된 범위
런타임/도구Express
런타임/도구express
문서 정리일2026-08-25
  • OS/CI 세부 값은 프로젝트마다 다르므로, 적용 전 로컬에서 동일 오류 메시지를 재확인한다.

1. 문제 정의

대용량 JSON 본문이나 URL-encoded 폼 데이터를 Express 서버로 전송했을 때, 다음과 같은 에러가 발생하며 요청이 413 상태 코드로 거부된다.

1
2
3
4
5
Error: request entity too large
    at module.exports (/.../node_modules/express/node_modules/connect/node_modules/raw-body/index.js:16:15)
    at json (/.../node_modules/express/node_modules/connect/lib/middleware/json.js:60:5)
    at Object.bodyParser [as handle] (/.../node_modules/express/node_modules/connect/lib/middleware/bodyParser.js:53:5)
    at next (/.../node_modules/express/node_modules/connect/lib/proto.js:193:15)

HTTP 상태 코드로는 413 Payload Too Large에 해당하며, 서버가 요청 본문(body)의 크기 제한을 넘어섰다고 판단했을 때 발생한다.

2. 표면 증상

  • 파일 업로드가 아닌 JSON을 통한 대용량 데이터 전송에서 주로 발생한다.
  • Express 기본 구성을 그대로 app.use(express.bodyParser()) 또는 app.use(bodyParser.json())으로 사용할 때 쉽게 재현된다.
  • 에러 로그는 요청 라우트가 실행되기 이전, 즉 본문 파싱 단계에서 이미 끝나 있어 라우트 핸들러 내부 코드는 전혀 도달하지 못한다.

증상 fingerprint

항목값
에러 메시지Error: request entity too large
HTTP 상태413 (Payload Too Large)
발생 지점body 파싱 미들웨어 (raw-body / json / bodyParser 스택)
기본 제한1MB = 1048576 bytes
흔한 오해“limit을 올렸는데도 안 된다” (실제 요청 단계에서 제한이 리셋됨, 또는 프록시에 또 다른 제한이 있음)

빠른 판단 기준: 에러 스택 최상단이 raw-body라면 Express 쪽 본문 파서 제한, 반면 브라우저 클라이언트가 아닌 nginx에서 413 Request Entity Too Large가 반환되면 프록시 제한을 의심해 본다.

3. 원인 탐구

Express가 요청 본문을 파싱하는 방식(과거 connect 시절)과 현재 개별 패키지(body-parser)의 기본 동작을 함께 이해해야 한다.

원인 후보 매트릭스

원인 후보확인 명령맞는 경우의 증상해결 방향
Express connect.json limit (1MB 기본)실행 로그로 json.js 실제 limit 값 출력JSON 요청 본문이 1MB를 초과bodyParser.json({limit: '50mb'})
URL-encoded 파라미터 수 초과 (parameterLimit, 기본 1000)요청 파라미터 개수 확인폼 필드가 수백~수천 개인 경우 413 발생bodyParser.urlencoded({limit:'50mb', extended:true, parameterLimit:50000})
리버스 프록시(nginx) 제한nginx 로그에서 413 확인, client_max_body_size 값 확인클라이언트가 nginx 레벨에서 413 응답을 받음nginx conf에 client_max_body_size 100M;
라우트별 limit 미설정라우트 정의 확인전역 설정은 됐는데 특정 라우트만 실패라우트 단위 bodyParser.json({limit}) 적용

왜 limit을 올렸는데도 실패하는가

잘 알려진 함정은 app.use(express.bodyParser({limit: '50mb'}))로 전역 limit을 올렸음에도, 실제 요청 파싱 스택인 내부 connect/raw-body 쪽에서 다시 기본값(1MB)으로 리셋되어 실제 요청 시점에는 여전히 1MB 제한이 적용되는 경우다. 실행 로그에서 초기 로드 때 Limit file size: 1048576(1MB)가 찍힌 뒤, 실제 요청 때 또다시 1MB가 찍힌다면 서버가 개발자가 지정한 limit을 파싱 단계에서 무시하고 있다는 뜻이다.

4. 근본 원인 분석

에러는 본문 파싱 미들웨어가 요청의 Content-Length가 자신의 limit 옵션보다 클 때 413을 던지며 파싱을 중단하기 때문에 발생한다.

  • Express 3.x 시절에는 express.bodyParser()가 내부적으로 connect 미들웨어의 raw-body → json → multipart 체인을 호출했고, 각 단계마다 limit 기본값 1MB가 하드코딩되어 있었다.
  • express.limit(), express.bodyParser({limit})로 전역 설정을 해도, 내부 connect가 파싱 단계에서 limit을 다시 기본값으로 덧쓰는 경우가 있어 설정이 “지나치게” 무시되는 경우가 관찰됐다.
  • 이후 Express는 body-parser를 별도 패키지로 분리했고, 이때부터는 express.json()이나 bodyParser.json()에 limit을 명시해야 본문 크기 제한이 실제로 반영된다.
  • 여기에 더해 nginx 같은 리버스 프록시를 앞에 두면 nginx의 client_max_body_size(기본 1MB)가 먼저 막아서 앱 레벨 설정과는 별개로 413이 발생할 수 있다.

즉, 문제를 한 줄로 정리하면 “Express 한 곳만 고치면 되는 것이 아니라, 요청이 통과하는 각 계층의 제한을 모두 확인해야 한다"는 점이다.

5. 코드 해결책

(1) 본문 파서에 limit 명시

1
2
3
4
5
// Express 4.x 이상 + body-parser 패키지
const bodyParser = require('body-parser');

app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));

json의 limit은 JSON 본문 크기 제한을, urlencoded의 limit은 URL-encoded 폼 본문 크기 제한을 각각 결정한다.

(2) 파라미터 수 제한도 함께 올리기

대형 폼(옵션이 수천 개인 경우)에서는 파라미터 수 제한이 별도로 걸리므로 함께 설정한다.

1
2
3
4
5
app.use(bodyParser.urlencoded({
  limit: '50mb',
  extended: true,
  parameterLimit: 50000
}));

parameterLimit은 URL-encoded 파라미터 최대 개수로 기본값이 1000이며, 이를 넘으면 413이 반환된다.

(3) 리버스 프록시(nginx)를 쓰는 경우

앱 코드만 고치는 것으로 부족할 수 있으므로, nginx 설정 파일(sites-available 등)에 프록시 계층의 제한도 올린다.

1
2
# /etc/nginx/sites-available/... (또는 server 블록 안)
client_max_body_size 100M;

(4) 요청 단계 제한 리셋 문제를 피하는 법

과거 connect 모듈 내부 파일을 직접 patch 하는 것은 임시방편이며, 패키지 업데이트와 다른 개발자 환경과 어긋난다. 반드시 애플리케이션 코드에서 limit을 명시하는 방식으로 간다.

6. 검증 명령

해결 후 요청이 실제로 통과하는지는 클라이언트 도구로 확인한다.

1
2
3
4
5
6
# 요청 본문 크기를 위계해 1MB 초과 데이터를 보내 413 재발 여부 확인
curl -X POST https://your-server/api/your-route \
  -H "Content-Type: application/json" \
  -d '{"payload": "10MB 크기의 대용량 데이터..."}'

# 응답이 200/201이면 성공, 413이 계속 나오면 다른 계층 제한이 남아 있는 것

또한 서버 실행 단계에서 limit 값이 50MB(52428800)로 출력되는지 로그를 함께 확인하면, 설정이 실제 파싱 스택에 반영되었는지 알 수 있다.

7. 향후 예방 조치

잘못된 해결책

  • connect 모듈 내부 파일을 직접 수정(patch)하는 것은 임시방편일 뿐이며, 패키지 업데이트로 되돌아가고 유지보수성이 크게 떨어진다. 권장하지 않는다.
  • limit: 0처럼 무기한으로 키우는 것은 요청 남횅(DoS) 위험이 커지므로, 비즈니스에 필요한 최솟값으로 정한다. (일반적인 보안 점검 기준이며, 환경에 따라 다를 수 있음)

재발 방지 체크

구분확인 항목
로컬 개발Express 본문 파서 limit 반영 여부, curl로 413이 사라졌는지 확인
CI/배포같은 설정이 배포 환경에 유지되는지, 코드 리뷰에서 limit 최솟값 통제
프로덕션nginx/로드밸런서 client_max_body_size이 앱 limit 이상인지, 요청 크기 매트릭 관찰

8. 마무리

DevTrace 결론

이 에러의 핵심은 요청 제한이 ‘한 군데’에만 있는 것이 아니라 Express body-parser와 리버스 프록시(nginx) 두 곳에 각각 존재하며, 표면적으론 limit 설정을 바꿔도 실제 요청 경로에서 적용되는 제한이 다를 수 있다는 점이다.

원문 출처는 문제 발견의 단서이며, 위 판단과 점검 항목은 DevTrace의 독자 분석이다.

DevTrace verdict: 이 문제의 핵심은 “Express 본문 파서 하나만 고치면 되는 것"이 아니라, 요청이 통과하는 Express 본문 파서와 리버스 프록시 계층의 제한을 함께 확인해야 한다는 점이다. 최신 환경에서는 body-parser의 json/urlencoded에 limit(필요하면 parameterLimit)을 명시적으로 주고, nginx를 쓴다면 client_max_body_size도 함께 올려야 413이 사라진다.


출처: StackOverflow — Error: request entity too large (질문 19917401, 채택 답변 투표 1615, 조회 83만 이상)