TechFeedTechFeed
Backend

Prisma P2022, 컬럼 없음, migrate | 로컬은 되고 프리뷰만 칸이 없으면?

프리즈마 P2022는 표는 있는데 그 칸이 지금 붙은 디비에 없는 줄입니다. generate 초록과 프리뷰 ALTER는 다른 칸이고, @map 이름과 카카오 콜백 500 뒤를 먼저 봅니다. Prisma, migrate, 슈퍼베이스, 버셀, Next.js, 카카오 로그인, 1인 개발자 기준. 2026년 9월 프리즈마·포스트그레스 공식 문서.

by

P2022는 표는 있는데 그 칸이 지금 붙은 디비에 없다는 뜻입니다. 스키마에 필드를 넣고 prisma generate만 하면 클라이언트는 그 칸을 고르고, 프리뷰 디비는 예전 표 그대로입니다.


로컬 도커에선 카카오 로그인이 되고 버셀 프리뷰만 콜백 500이 나는 패턴이 여기입니다. 제가 사이드 프로젝트 유저 표에 kakaoId를 넣었을 때도 generate는 초록이었습니다. 칸을 만드는 쪽은 migrate입니다.


호스트가 안 열리는 P1001, 표 이름 자체가 없는 P2021과 칸을 섞지 마세요. 공식 메시지는 프리즈마 오류 코드에 그 컬럼이 현재 디비에 없다고 적혀 있고, 칸을 넣는 절차는 마이그레이션 문서에 있습니다.


generate만 초록이면 칸은 아직 없다

클라이언트만 다시 만든 겁니다. 표 ALTER는 다른 명령입니다.


프리즈마 클라이언트는 스키마 파일을 읽고 SELECT 목록을 만듭니다. 유저 모델에 kakaoId를 넣으면 다음 조회부터 그 칸을 고릅니다. generate는 타입과 쿼리 코드만 바꿉니다. 포스트그레스 표에 칸을 붙이는 SQL은 migrate가 실행합니다.


그래서 로컬에서 generate를 돌리고 바로 카카오 콜백을 누르면, 로컬 디비에 이미 migrate를 한 적 있으면 통과합니다. 프리뷰는 예전에 만든 유저 표만 있고 kakaoId 칸이 없습니다. 빌드 로그는 초록인데 런타임만 P2022가 납니다. 한국에서 맥으로 짜고 버셀 프리뷰에 올리는 1인 스택에서 자주 만납니다.


혼자 넥스트 사이드를 돌리면 스키마를 고친 날 밤에 generate만 하고 푸시하는 일이 많습니다. 타입 에러가 사라져서 끝난 줄 압니다. 다음날 프리뷰 카카오 버튼이 500을 내면 그때야 칸이 없었던 겁니다. 로컬 도커는 어제 마이그레이션을 돌려 둔 상태라 증상이 안 납니다. 화면이 나와도 프리뷰 표의 칸 목록을 열기 전에는 끝난 게 아닙니다.


먼저 기억할 것 | 메시지에 찍힌 칸 이름을 복사해 프리뷰 디비에서 찾으세요. 표 목록이 보여도 그 칸이 없으면 P2022입니다. 표 이름 자체가 없으면 P2021입니다.


표는 있고 칸만 없을 때 먼저 볼 네 줄

에러 코드, 칸 이름, 지금 붙은 URL, information_schema 네 줄이면 갈립니다.


보면먼저 할 일
코드P2022표 없음·연결 거절과 분리
칸 이름User.kakaoId 또는 users.kakao_id스키마 필드가 아니라 디비 칸 이름
URL로컬은 되고 프리뷰만 실패버셀 프리뷰 DATABASE_URL이 로컬과 같은지
information_schema표는 있고 칸 목록에 그 이름이 없음migrate deploy를 그 URL에 실행
@map필드 kakaoId, 칸 kakao_id클라이언트가 찾는 이름은 맵 쪽

포스트그레스는 없는 칸을 42703으로 거절합니다. 프리즈마는 그 드라이버 오류를 P2022로 감쌉니다. 코드만 보지 말고 메시지에 찍힌 칸 문자열을 그대로 복사하세요. 컬럼 목록은 information_schema.columns에 있습니다.


호스트까지 못 붙으면 P1001입니다. 여기서는 TCP는 열린 다음, SELECT 목록의 한 칸이 없는 줄만 봅니다.


에러에 찍힌 칸이 프리뷰 표에 있는지
npx prisma migrate status # DATABASE_URL은 프리뷰에 붙은 그 값으로 SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'User'; # @@map("users")면 table_name = 'users'
서버 랙 통로, 스키마와 실제 디비 칸이 어긋난 배포를 떠올리는 장면
클라이언트 타입은 맞춰 두고 프리뷰 표만 예전 칸이면 P2022가 난다

프리뷰에 칸을 넣는 순서

로컬에서 마이그레이션 파일을 커밋하고, 프리뷰 URL에 deploy를 돌립니다.


개발 중 초안은 prisma db push로 로컬 표를 맞출 수 있습니다. 프리뷰와 프로덕션은 히스토리가 남는 prisma migrate deploy가 맞습니다. generate를 빌드에 넣었다고 칸이 생기지 않습니다. 버셀 빌드가 초록이어도 프리뷰 주소의 표에 칸이 있는지는 따로 확인합니다.


슈퍼베이스를 쓰면 대시보드 SQL과 프리즈마 마이그레이션이 동시에 칸을 만듭니다. 대시보드에서 칸을 먼저 붙이고 스키마만 고치면 로컬 migrate dev가 드리프트를 봅니다. 칸을 넣는 길은 하나로 고정하세요. 공식 안내는 초안용 푸시슈퍼베이스 프리즈마에 있습니다.


제가 쓰는 버셀 프리뷰는 프로덕션과 같은 슈퍼베이스 프로젝트를 가리키지 않습니다. 프리뷰용 디비를 따로 두면 generate가 성공해도 그 디비의 유저 표는 예전입니다. 배포 훅에 마이그레이션 적용을 넣지 않으면 칸은 안 생깁니다. 콘솔에서 표만 열어 보면 유저 행은 보이니, 칸 목록까지 내려봐야 합니다.


로컬 초안과 프리뷰 배포를 나누기
# 로컬 초안, 히스토리 없이 표만 맞출 때 npx prisma db push # 프리뷰·프로덕션, 마이그레이션 파일을 적용 npx prisma migrate deploy # 클라이언트는 그 다음 npx prisma generate
  • [ ] 에러 메시지에서 칸 이름을 그대로 복사했다
  • [ ] 프리뷰 DATABASE_URL로 information_schema를 조회했다
  • [ ] 표는 있고 그 칸만 없는 것을 확인했다
  • [ ] 마이그레이션 파일이 저장소에 커밋돼 있다
  • [ ] 그 URL에 migrate deploy를 돌린 뒤 같은 SELECT를 다시 봤다

db push를 프리뷰에 습관처럼 쓰지 마세요 | 초안용입니다. 이미 migrate 히스토리가 있는 디비에 push를 섞으면 다음 deploy가 어긋납니다. 프리뷰는 deploy 한 칸으로 맞춥니다.


맵 이름과 실제 칸이 다를 때

클라이언트가 찾는 이름은 자바스크립트 필드가 아니라 맵에 적힌 칸입니다.


필드가 kakaoId여도 @map("kakao_id")면 SELECT는 kakao_id를 고릅니다. 대시보드에서 칸을 kakaoId로 만들었으면 맵과 다릅니다. 반대로 맵 없이 필드만 kakaoId면 프리즈마는 따옴표 친 "kakaoId"를 찾습니다. 포스트그레스 기본 식별자는 소문자라, 따옴표 없이 만든 kakaoId는 kakaoid가 됩니다.


표 이름도 같습니다. 모델 User에 @@map("users")가 있으면 information_schema의 table_name은 users입니다. User로 조회하면 칸이 없는 게 아니라 표를 잘못 고른 겁니다. 모델·필드 매핑은 프리즈마 모델 문서를 봅니다.


필드 이름과 디비 칸 이름을 따로 적기
model User { id String @id @default(cuid()) kakaoId String? @unique @map("kakao_id") @@map("users") } # 클라이언트가 찾는 칸은 users.kakao_id # 대시보드에 "kakaoId"만 있으면 P2022
모니터와 키보드가 있는 책상, 스키마 파일과 디비 칸 이름을 대조하는 작업 자리
필드 kakaoId와 칸 kakao_id는 다른 문자열이다. 맵을 먼저 읽는다

카카오 콜백 500 뒤에 숨은 컬럼

인가 코드 교환은 됐고, 유저 upsert에서 P2022가 난 겁니다.


카카오 REST는 토큰과 프로필을 돌려줍니다. 넥스트 라우트가 그 아이디를 유저 표에 넣을 때 스키마에만 있는 칸을 쓰면 500입니다. 콘솔 리다이렉트 URI 오류 KOE006과 자리가 다릅니다. URI가 맞는데 콜백만 500이면 디비 칸을 의심하세요. 카카오 쪽 절차는 카카오 REST API에 있습니다.


버셀 프리뷰 환경 변수에 디비 주소가 있어도, 그 디비에 마이그레이션을 안 돌렸으면 칸은 없습니다. 환경 변수 칸은 버셀 환경 변수 문서입니다. 주소가 맞는지와 칸이 있는지는 다른 확인입니다.


카카오 개발자 콘솔의 리다이렉트 주소를 세 번 고치고 나서야 서버 로그를 본 적이 있습니다. 인가 코드는 이미 넘어 왔고, 저장 한 줄에서 칸이 없었습니다. 콘솔 주소를 의심하기 전에 프리즈마 코드가 찍혔는지부터 보세요. 카카오 오류 번호가 아니면 카카오 칸이 아닙니다.


P2021, P1001, P2002와 칸이 다르다

표 없음, 호스트 불가, 유니크 충돌은 각각 다른 줄입니다.


코드무엇이 없거나 막히나다음 글
P2022표는 있고 칸이 없음이 글
P2021표 이름 자체가 없음테이블 없음
P1001호스트:포트 TCP가 안 열림연결 불가
P2002유니크 칸이 이미 참중복 키
ECONNREFUSEDlocalhost가 거절도커 5432

조회는 되고 넣기만 403이면 행 수준 보안입니다. 칸이 없어서가 아닙니다. 그 칸은 RLS 넣기 막힘에서 다룹니다.


트리거가 지운 칸을 아직 참조하면, 메시지에 없는 이름이나 NEW가 찍힐 수 있습니다. 마이그레이션으로 칸을 빼기 전에 트리거를 같이 고치세요. 예외 처리 형식은 프리즈마 예외 처리를 따릅니다.


데이터센터 서버실 통로, 프리뷰 디비에 칸을 맞추기 전에 연결부터 확인하는 자리
연결이 된 다음에야 칸 목록을 본다. P1001과 P2022는 순서가 다르다

참고 자료


내부 연계: P2021 테이블 없음, P1001 연결, P2002 유니크, 도커 ECONNREFUSED, RLS 403


인용한 동작은 2026년 9월 공개 문서 기준입니다. 프리즈마 7의 migrate deploy·db push를 기준으로 적었습니다.


자주 묻는 질문

로컬은 되고 프리뷰만 P2022입니다. 클라이언트가 잘못된 건가요?

클라이언트보다 프리뷰 표입니다. generate는 로컬과 프리뷰가 같은 스키마를 읽습니다. 로컬 도커에는 칸이 있고 프리뷰 슈퍼베이스에는 없습니다. 프리뷰 DATABASE_URL로 information_schema를 조회한 뒤 migrate deploy를 그 URL에 돌리세요.


P2021과 무엇이 다른가요?

P2021은 표 이름 자체가 없습니다. P2022는 표는 있고 칸만 없습니다. 유저 표가 보이는데 kakaoId만 없으면 이 글입니다. 표 목록이 비어 있으면 테이블 없음 글을 보세요.


prisma generate를 빌드에 넣으면 끝나나요?

끝나지 않습니다. generate는 타입과 쿼리 코드만 만듭니다. ALTER는 migrate deploy가 실행합니다. 빌드 초록과 프리뷰 칸 목록은 다른 확인입니다.


스키마 필드와 디비 칸 이름이 다릅니다.

@map에 적힌 칸을 찾습니다. kakaoId 필드에 @map("kakao_id")면 디비에는 kakao_id가 있어야 합니다. 대시보드에 kakaoId만 있으면 P2022입니다. @@map으로 표 이름도 같이 맞춰 보세요.


카카오 로그인이 500입니다. 리다이렉트 URI부터 볼까요?

KOE006이면 URI입니다. 인가 코드 교환까지 되고 유저 저장에서 P2022면 칸입니다. 로그에 프리즈마 코드가 있으면 콘솔 주소보다 표 칸을 먼저 보세요.


db push로 프리뷰를 맞춰도 되나요?

로컬 초안용입니다. 이미 migrate 히스토리가 있는 프리뷰에 push를 섞으면 다음 deploy가 어긋납니다. 프리뷰는 migrate deploy 한 길로 칸을 넣으세요.


P2022는 지금 붙은 디비의 그 표에 그 칸이 없다는 뜻입니다. 메시지 칸 이름을 복사하고, 프리뷰 URL로 칸 목록을 본 다음, migrate deploy를 돌리세요. generate 초록은 끝이 아닙니다. 관련 글: P2021, P1001, P2002.


PrismaP2022컬럼migratedb push슈퍼베이스버셀PostgreSQL넥스트카카오백엔드마이그레이션개발자

함께 보면 좋은 문제 해결

EXPLORE / Backend

이어서 읽어보기

전체 토픽 둘러보기