Next.js 16 한글 slug 404 — 빌드는 성공했다
사이트맵 59개를 전수 검사하니 한글 제목 12편만 전부 404였다. 11일 동안 빌드는 매일 통과 신호를 냈다.
블로그를 보다가 404가 간간히 보인다고 말했다. 간간히면 캐시나 배포 타이밍 문제쯤으로 넘기게 된다. 그래서 사이트맵에 올라간 글 주소 59개를 전부 눌러서 응답 코드를 재 봤다.
한글 제목 글 12편이 전부 404, 영문 제목 글 47편이 전부 200이었다. 간간히가 아니라 제목이 한글이면 예외 없이 죽는 규칙적인 고장이었다.
첫 한글 제목 글이 8월 15일자였다. 그날부터 11일째 그 상태로 굴러가고 있었다.
맥의 NFD 를 의심했고, 틀렸다
제일 먼저 의심한 건 맥의 한글 파일명이었다. 맥은 한글 파일명을 NFD(자음·모음을 분해한 형태)로 저장한다. 「한」이 한 글자가 아니라 「ㅎ+ㅏ+ㄴ」 세 조각으로 들어간다. 코드 안에 적은 한글은 결합된 형태(NFC)라 눈으로 같아 보이는데 비교하면 다르다. 전에 이 함정에 데인 적이 있어서 바로 그쪽으로 갔다.
재 보니 디스크도 git 도 전부 NFC 로 통일돼 있었다. 아니었다. 여기서 "그럼 뭐지" 하고 멈추지 않은 게 갈림길이었다.
방향을 돌린 건 응답 헤더 한 줄이었다.
HTTP/2 404
x-nextjs-prerender: 1
prerender: 1 은 요청이 왔을 때 실패한 게 아니라, 빌드할 때 만들어 둔 파일을 그대로 내줬다는 뜻이다. 즉 404 화면 자체가 빌드 결과물로 구워져 배포된 것이다. 그 한 줄이 없었으면 서버 쪽을 한참 뒤졌을 것이다.
그 다음은 로컬에서 빌드해 산출물을 열어 보는 것으로 끝났다. 한글 글 12편의 HTML 이 전부 Next 의 에러 페이지였다. 재현율 100%. 마지막으로 페이지에 임시로 값을 찍는 코드를 심고 빌드해서, 실제로 넘어오는 문자열을 눈으로 확인했다.
퍼센트 인코딩된 채로 넘어온다
Next.js 16 이 글을 미리 만들 때, 주소에서 뽑은 글 이름을 퍼센트 인코딩된 채로 넘긴다.
받아야 하는 값 : 2026-08-15-경고만-달고-결론은-안-바꿨다
실제로 오는 값 : 2026-08-15-%EA%B2%BD%EA%B3%A0%EB%A7%8C-… (114자)
코드는 2026-08-15-%EA%B2%BD….md 라는 이름의 파일을 찾는다. 그런 파일은 없으니 「글 없음」으로 판정한다. 영문 제목은 인코딩해도 글자가 그대로라 멀쩡하다. 한글 글만 골라서 죽는다.
글을 찾기 전에 주소를 원래 글자로 되돌리는 함수 하나를 넣었다.
function decodeSlug(slug: string): string {
try { return decodeURIComponent(slug); } catch { return slug; }
}
고친 곳은 한 파일 한 함수다. 그 함수를 부르는 곳이 글 상세 페이지 둘뿐이었고(본문과 공유 카드용 메타데이터), 한 곳을 고치니 둘 다 나았다. 빌드 산출물 59편을 다시 전수 검사하니 404가 0편이 됐다.
주소를 영문으로 바꾸는 안도 있었지만 고르지 않았다. 이미 살아난 주소를 나중에 또 바꾸면 그 12개가 다시 죽는다. 어느 쪽으로 가든 이 한 줄이 먼저다.
관문이 있었는데 안 걸렸다
이 블로그는 자동으로 글을 발행한다. 그래서 빌드가 깨지면 그날 글이 안 나가도록 발행 절차에 npm run build 를 관문으로 세워 뒀다. 조용한 실패를 막으려고 만든 장치다.
그 관문이 11일 동안 매일 통과 신호를 냈다. 빌드가 성공했기 때문이다. 실제로 만들어진 게 404 페이지였을 뿐이다.
- 빌드가 통과한다
- 타입체크도 통과한다
- 빌드 로그는 한글 주소를 라우트 목록에 버젓이 찍어 준다
- 만들어진 게 404 라는 말은 어디에도 없다
빌드가 확인해 주는 건 터지지 않았다 까지고, 만들어진 게 맞는 물건인가 는 산출물을 열어 봐야 안다. 그리고 이 종류의 실패는 에러가 없어서 아무 신호도 안 준다. 누군가 우연히 그 글을 눌러 보기 전까지 계속 굴러간다. 이 12편도 내가 눈으로 보고 "간간히 404가 보인다"라고 말해서 발견됐다.
검색엔진은 그 12개 주소를 404 로 읽어 갔다. 사이트맵에는 계속 실려 있었으니 다시 읽어 가면서 회복되겠지만, 11일치 색인 기회는 그냥 날아간 것이다.