TechFeedTechFeed
Programming Languages

ERR_PACKAGE_PATH_NOT_EXPORTED, 서브패스, exports | 패키지는 있는데 깊은 경로만 막히면?

ERR_PACKAGE_PATH_NOT_EXPORTED는 패키지는 있는데 exports에 없는 서브패스를 불러 노드가 거절할 때 나는 코드입니다. 공개 입구로 바꾸거나, 내 패키지면 그 경로를 exports에 적습니다. node_modules 수정은 다음 설치에서 돌아옵니다. Node.js, package.json, 빌드, 한국 1인 개발. 2026년 10월 문서.

by

ERR_PACKAGE_PATH_NOT_EXPORTED는 패키지가 디스크에 있어도, package.json의 exports에 없는 서브패스를 불러 노드가 거절할 때 납니다. node_modules를 지우기 전에, 에러에 찍힌 이름 뒤 경로가 exports 목록에 있는지부터 보세요.

로컬에서 깊은 경로가 어제까지 열리다가, 그 패키지 메이저를 올린 뒤에만 이 줄이 나는 일이 있습니다. 1인으로 넥스트를 새벽 배포하면 빌드 로그에 이 코드만 남고 화면은 빈 채로 끝납니다. 한국 시간 프리뷰에서 특히 자주 보입니다.


공개된 입구만 불러 고치고, 내가 소유한 패키지면 그 서브패스를 exports에 적습니다. 근거는 Node.js 서브패스 exports입니다.


패키지는 있는데 왜 이 줄인가

exports에 없는 서브패스라 노드가 거절한 줄입니다.


패키지 이름 자체가 없으면 Cannot find module이 먼저 납니다. 폴더는 있는데 pkg/dist/internal.js처럼 안쪽 파일을 직접 열면, exports가 그 길을 막습니다. 노드 12.7 이후 서브패스 exports가 생기고, exports 필드가 있는 패키지는 적힌 입구만 공개합니다.


메시지는 보통 이렇게 생겼습니다. Package subpath './dist/internal.js' is not defined by "exports". 따옴표 안 경로와 node_modules/그패키지/package.json을 나란히 보면 됩니다. 파일이 디스크에 있어도 목록에 없으면 같은 코드입니다.


메이저 업이 입구를 줄이는 경우가 많습니다. 어제 lodash/get이 열렸는데 오늘 버전이 exports로 루트만 남기면, 설치는 초록이고 빌드만 이 줄에서 죽습니다. 락을 지우는 순서는 그 다음입니다.


먼저 기억할 것 | 에러의 서브패스 문자열을 그대로 복사해 그 패키지 exports 키와 비교하세요. 파일이 있는 것과 공개된 것은 다른 칸입니다.


봉인된 상자가 노트북 옆에 놓인 책상. 패키지가 있어도 공개 입구만 열리는 장면
상자가 책상 위에 있어도, 적힌 입구가 아니면 노드는 안을 열지 않는다

먼저 가를 세 칸

서브패스, 확장자, import와 require 조건이면 원인이 갈립니다.


칸증상먼저 할 일
서브패스 없음루트 import는 되고 깊은 경로만 실패공개된 입구로 바꿈
확장자pkg/sub 는 되고 pkg/sub.js 만 실패, 또는 반대exports 키의 .js 유무를 맞춤
조건require는 되고 import만 실패import 조건에 그 경로가 있는지 확인
null 대상내부 폴더만 일부러 막힘우회하지 말고 공개 API를 씀
패키지 없음이름 자체가 없음이 코드가 아님. 모듈 없음 글

다섯 번째 칸은 Cannot find module입니다. 설치 트리를 못 만드는 줄은 ERESOLVE입니다. 여기서는 패키지는 깔렸고 exports가 길을 닫은 경우만 봅니다.


exports 키만 찍기
node -p "JSON.stringify(require('./node_modules/some-pkg/package.json').exports, null, 2)" # 에러의 './dist/internal.js' 가 키에 없으면 공개 입구가 아니다

공개 입구로 바꾸기

남이 만든 패키지면 적힌 입구만 부릅니다.


node_modules 안의 exports를 지우는 수정은 다음 npm ci에서 돌아옵니다. 프리뷰는 매번 깨끗이 설치하므로, 로컬에서만 잠시 열리는 수가 있습니다. 고친 것처럼 보여도 배포 로그는 같은 서브패스로 다시 죽습니다.


호출부를 패키지가 문서에 적은 이름으로 바꿉니다. 깊은 파일이 필요하면 그 패키지의 공개 함수가 같은 일을 하는지 먼저 봅니다. 없다면 버전을 exports가 그 길을 열어 둔 범위로 고정합니다. 락에 그 버전이 남아야 다음 설치가 같습니다.


조건부 exports에서 import와 require가 다른 파일을 가리키면, 넥스트 빌드의 서버 번들과 스크립트의 require가 갈립니다. 한쪽에만 서브패스가 있으면 다른 쪽만 이 코드를 냅니다. 둘 다 필요한 입구인지 키를 읽으세요.


혼자 사이트를 올리며 의존성을 올리다 보면, 설치 로그는 초록인데 묶음만 이 줄에서 멈춥니다. 그때 폴더를 통째로 지우고 다시 받는 버릇이 생깁니다. 다시 받아도 공개 목록은 그대로라 같은 깊은 경로가 또 거절됩니다. 고칠 자리는 호출하는 쪽의 경로 문자열입니다. 내가 만든 공용 묶음이면 목록에 길을 한 줄 추가하고, 그 변경을 저장소에 남깁니다. 배포 기계는 매번 깨끗한 설치를 하므로, 손본 설치 폴더는 증거가 되지 않습니다.


새벽에 미리보기만 죽고 내 컴퓨터는 살아 있으면, 두 곳의 잠금 파일이 같은지부터 봅니다. 한쪽에만 큰 판을 올려 입구가 줄었는데 다른 쪽은 옛 잠금을 쓰면 증상이 갈립니다. 잠금을 맞춘 뒤에도 깊은 경로 호출이 남아 있으면 빌드는 다시 멈춥니다. 목록을 읽고 호출을 공개된 이름으로 바꾸는 순서가 설치보다 앞입니다.


공용 묶음을 여러 앱이 같이 쓰면, 한 앱만 안쪽 파일을 부르다 배포가 멈춥니다. 그 앱의 호출을 고치거나, 공용 묶음이 그 길을 정식으로 열어야 합니다. 문을 열어 줄 때는 이름과 파일을 짝으로 적고, 숨길 폴더는 빈 대상으로 닫습니다. 닫아 둔 문을 앱마다 우회하면 다음 판에 다시 깨집니다. 오늘 고친 한 줄이 저장소에 들어갔는지, 잠금 파일과 함께 남았는지만 확인하면 이 코드는 다음 배포에서 사라집니다.


깊은 경로를 공개 입구로
// 막히는 줄 import internal from 'some-pkg/dist/internal.js' // 패키지 exports의 "." 만 공개된 경우 import somePkg from 'some-pkg'
  • [ ] 에러의 서브패스 문자열을 복사했다
  • [ ] 그 패키지 package.json의 exports 키를 열었다
  • [ ] .js 유무와 import/require 조건을 비교했다
  • [ ] node_modules 안의 exports를 고치지 않았다
  • [ ] 호출을 공개 입구로 바꾸거나, 버전을 락에 고정했다

사람 없는 서버 랙 통로. 설치는 끝났는데 입구만 막힌 배포 장면
설치가 끝나 랙이 서 있어도, 공개하지 않은 문은 열리지 않는다

내 패키지면 exports에 적기

워크스페이스 패키지는 서브패스 키를 직접 추가합니다.


모노레포에서 packages/shared를 만들고 exports에 "."만 두면, 앱이 shared/kakao를 부를 때 이 줄이 납니다. 파일을 추가한 것만으로는 공개가 아닙니다. 키를 적어야 합니다.


키가 많으면 "./feature/*.js" 패턴을 쓸 수 있습니다. 노드 문서는 개수가 적으면 경로를 하나씩 적으라고 합니다. 감추고 싶은 폴더는 대상에 null을 넣습니다. null로 막힌 길을 앱에서 다시 여는 우회는 다음 배포에서 다시 깨집니다.


패키지 안의 비공개 파일은 imports의 #internal으로 둡니다. 샵 경로는 그 패키지 안에서만 열립니다. 바깥 앱이 샵을 부르면 또 다른 거절이니, 앱에는 서브패스 exports만 넘기세요.


서브패스 하나를 공개
{ "name": "@shop/shared", "exports": { ".": "./index.js", "./kakao.js": "./src/kakao.js" } }

null은 일부러 닫은 문 | 패키지가 "./internal/*": null로 적었다면 그 에러는 버그가 아닙니다. 공개 함수로 돌아가세요.


모듈 없음과 다른 줄이다

이름이 없는 줄과, 이름은 있는데 길이 닫힌 줄은 고치는 파일이 다릅니다.


Cannot find module은 node_modules 사다리에서 패키지 이름을 못 찾은 경우입니다. 작업 폴더가 홈이거나 철자가 다를 때 납니다. ERR_PACKAGE_PATH_NOT_EXPORTED는 그 폴더를 찾은 다음, exports 맵이 서브패스를 거절한 경우입니다. 둘 다 모듈 이야기로 보여도 다음 명령이 다릅니다.


웹팩이 MD4에서 죽는 줄은 ERR_OSSL_EVP_UNSUPPORTED입니다. 빌드 해시와 패키지 입구를 한 수정으로 섞지 마세요. 엣지 런타임이 fs를 거절하는 줄도 따로입니다. 로그 첫 코드가 exports면 이 글의 순서만 보면 됩니다.


메시지무엇을 거절하나다음
ERR_PACKAGE_PATH_NOT_EXPORTEDexports에 없는 서브패스이 글
Cannot find module패키지 이름, 작업 폴더모듈 없음 글
ERESOLVE설치 중 피어 충돌피어 충돌 글

참고 자료


내부 연계: 모듈을 찾을 수 없음, 피어 의존성 충돌, 빌드 해시가 OpenSSL에서 죽을 때, 엣지 런타임이 노드 모듈을 거절할 때.


인용한 동작은 2026년 10월 Node.js 패키지 문서 기준입니다.


자주 묻는 질문

node_modules를 지워도 같은 서브패스가 막힙니다.

설치가 아니라 공개 목록 문제입니다. 다시 깔아도 그 버전의 exports는 같습니다. 호출 경로를 공개 입구로 바꾸거나, 내 패키지면 키를 추가하세요.


로컬은 되는데 프리뷰 빌드만 이 코드입니다.

로컬 node_modules의 exports를 손으로 고쳤거나, 락과 다른 버전이 남아 있을 때 그렇습니다. 프리뷰는 npm ci로 락을 그대로 깔므로, 저장소에 커밋된 호출과 락을 맞추세요.


require는 되고 import만 실패합니다.

조건부 exports입니다. require 키에만 그 서브패스가 있고 import 키에는 없을 수 있습니다. 넥스트 서버 번들은 import 조건을 탑니다. 두 조건의 키를 같이 보세요.


확장자만 빼면 열리나요?

키가 ./sub.js 인지 ./sub 인지에 달렸습니다. 노드 문서는 확장자를 붙인 입구와 뺀 입구를 패키지 작성자가 고르라고 합니다. 추측으로 빼지 말고 키를 복사하세요.


내부 파일을 null로 막아 두었습니다. 앱에서 열 방법이 있나요?

그 대상은 일부러 닫힌 문입니다. 소비자 쪽에서 우회하면 다음 버전에 다시 막힙니다. 패키지가 공개한 함수로 바꾸세요.


Cannot find module과 어떻게 구분하나요?

코드 문자열이 ERR_PACKAGE_PATH_NOT_EXPORTED 이고 서브패스가 찍히면 이 글입니다. 패키지 폴더 자체가 없다고 하면 작업 폴더와 설치부터 보세요. 피어 충돌은 설치가 끝나기 전의 로그입니다.


ERR_PACKAGE_PATH_NOT_EXPORTED는 패키지는 찾았는데 exports가 그 서브패스를 안 연다는 뜻입니다. 목록에 있는 입구로 호출을 바꾸고, 내 패키지면 키를 추가하세요. node_modules 안의 JSON을 고치는 수정은 다음 설치에서 사라집니다. 관련 글: 모듈 없음, 피어 충돌.


ERR_PACKAGE_PATH_NOT_EXPORTEDexports서브패스Node.jspackage.json빌드모듈개발

함께 보면 좋은 문제 해결

EXPLORE / Programming Languages

이어서 읽어보기

전체 토픽 둘러보기 →