운영 로그에 하루에 몇 번씩 이 에러가 찍힙니다. 항상 나는 게 아니라 특정 요청에서 가끔만 나서 재현이 정말 안 돼요.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (node:_http_outgoing:...)
at ServerResponse.header (.../express/lib/response.js:...)핸들러 안에서 조건 분기해서 res.json을 여러 번 부를 일은 없다고 생각했는데, 문제 라우트를 아무리 봐도 res를 두 번 보내는 데를 못 찾겠습니다. 어떤 요청은 되고 어떤 요청은 안 되고... 대체 뭘 봐야 할까요?
댓글 2
가장 많은 건 res.json 뒤에 return을 안 붙인 early-return입니다. if (!user) { res.status(404).json(...) } 하고 return을 안 하면 아래 정상 응답 코드까지 그대로 실행돼서 두 번 보내집니다. 순수 동기라면 항상 터지겠지만 중간에 await가 끼면 타이밍 따라 가끔만 터지죠. if 블록마다 return res.json(...) 형태로 바꾸세요.
두 번째는 정상 경로와 catch가 겹치는 경우예요. try 안에서 res.json으로 응답을 이미 보냈는데 그 아래 코드가 throw해서 catch로 가고, catch에서 또 res.status(500)을 보내는 식입니다. 응답을 보낸 뒤의 코드는 catch에 안 걸리게 구조를 잡아야 해요.
세 번째는 요청 타임아웃이나 클라이언트 abort 핸들러에서 res를 보내는데 정상 응답과 겹치는 경우고요.
디버깅은 이렇게 하세요. 문제 라우트에서 res.json 부르기 직전에 if (res.headersSent) { console.trace('double send'); return } 를 넣으면 두 번째로 보내려는 지점의 스택이 그대로 찍힙니다. 그 한 방이면 범인이 바로 나와요. 그리고 앞으로 응답은 습관적으로 return res.xxx() 로 쓰는 걸 권합니다.