학습 목표와 사전 지식
목표: undefined 선택 필드 오류를 원격 쓰기 없이 재현하고 저장 객체를 명시적으로 구성합니다.
사전 지식: JavaScript undefined/null, Node.js ESM, Firestore 쓰기
Unsupported field value: undefined는 값 직렬화 단계에서 발생할 수 있습니다. Rules를 열거나 재시도 횟수를 늘려 해결할 문제가 아닙니다. 선택 필드는 값이 없을 때 생략할지 null로 저장할지 먼저 정하세요.
환경·재현 범위
Node.js와 Firebase Web SDK 모듈형 API를 사용합니다. scripts/before.mjs와 scripts/after.mjs는 각각 전체 파일이며 npm install firebase@12.19.0 후 node로 실행합니다. writeBatch().set()만 호출하고 commit()하지 않아 서버에 문서를 쓰지 않습니다. 이 구분 덕분에 직렬화와 원격 권한을 따로 확인할 수 있습니다.
scripts/before.mjs · 전체 재현 파일
import { initializeApp, deleteApp } from 'firebase/app';
import { doc, getFirestore, writeBatch } from 'firebase/firestore';
const app = initializeApp({ projectId: 'demo-undefined' }, 'before');
try {
const db = getFirestore(app);
writeBatch(db).set(doc(db, 'profiles', 'fixture-user'), { name: '학습자', phone: undefined });
} finally {
await deleteApp(app);
}

수정 방법: 저장할 필드를 선택하기
scripts/after.mjs의 makeProfile에서 name을 확인하고 phone이 정의된 경우에만 필드를 만듭니다. Object.fromEntries로 모든 폼 필드를 복사하면 앞으로 추가된 admin 같은 필드까지 저장할 수 있고, 중첩 undefined도 그대로 남습니다. 허용할 필드를 명시하면 입력 계약을 검토하기 쉽습니다.
scripts/after.mjs · 전체 수정 파일
import { initializeApp, deleteApp } from 'firebase/app';
import { doc, getFirestore, writeBatch } from 'firebase/firestore';
export function makeProfile(form) {
if (typeof form.name !== 'string' || !form.name.trim()) throw new Error('이름 필요');
if (form.phone !== undefined && typeof form.phone !== 'string') throw new Error('전화번호 형식');
return {
name: form.name.trim(),
...(form.phone !== undefined ? { phone: form.phone.trim() } : {})
};
}
const app = initializeApp({ projectId: 'demo-undefined' }, 'after');
try {
const db = getFirestore(app);
const profile = makeProfile({ name: '학습자', phone: undefined });
writeBatch(db).set(doc(db, 'profiles', 'fixture-user'), profile);
console.log('직렬화 통과: phone 필드 생략');
} finally {
await deleteApp(app);
}
undefined·null·삭제는 다릅니다
필드를 생략하는 것은 그 키를 payload에 넣지 않는 것입니다. setDoc 기본 덮어쓰기, setDoc merge, updateDoc에서 생략이 기존 데이터에 미치는 영향은 다릅니다. null은 실제 저장되는 값이고 기존 필드 제거는 deleteField() 같은 삭제 연산을 사용합니다. JSON stringify/parse는 undefined 외에도 날짜·특수 객체 표현을 바꾸므로 만능 정리 함수로 쓰지 마세요.
ignoreUndefinedProperties를 쓰는 경우
initializeFirestore(app, { ignoreUndefinedProperties: true })는 초기 인스턴스를 만들 때 정하는 정책입니다. getFirestore로 사용한 뒤 뒤늦게 바꾸는 설정으로 안내하지 않습니다. 객체의 선택 필드를 건너뛰는 것과 배열 안의 undefined 처리는 같지 않으며 모든 잘못된 입력을 수정해 주지 않습니다. 정책으로 누락을 허용해도 필수 필드·타입 검사는 남겨야 합니다.
같은 명령으로 비교하기
node scripts/before.mjs는 undefined 관련 예외와 비정상 종료가 기대 결과입니다. node scripts/after.mjs는 phone을 생략한 객체의 직렬화 통과를 출력합니다. name 누락과 phone 숫자를 넣으면 입력 검사에서 거부되어야 합니다. 실제 commit 성공·Rules·네트워크·브라우저 화면은 이 검사 범위에 포함하지 않습니다.
실제 실행 결과
2026-09-13 검증: Node.js 24.19.0, firebase 12.19.0에서 before는 invalid-argument(종료 1), after는 직렬화 통과(종료 0)를 실제 확인했습니다. commit 호출은 하지 않았습니다.
직접 확인할 결과
실제 SDK before 실패/after 통과 검사 예정
입력 타입·필수값 경계 검사
commit·Auth·Rules 미실행
검증 범위와 기준일
공식 문서 확인일: 2026-09-13. 웹 SDK 예제는 모듈형 API 기준입니다. 이 글의 코드·구조 정적 검토와 실제 클라우드 인증·저장·배포 검증을 구분합니다. 본인 개발 Firebase 프로젝트의 실제 인증·권한·배포 요청은 이 편집 환경에서 실행하지 않았습니다.
실습 파일 다운로드
before·after 전체 코드와 README ZIP
이어서 학습하기
공식 문서
이 글이 도움이 되었나요?
Firebase 학습 순서
필수 13개 · 전체 19개
읽음 기록 관리
전체 과정 목차 (19개)
- 필수 길잡이 · Firebase 실무 로드맵: Auth, Firestore, Storage, Functions
- 필수 학습 · Firebase 초기화 구조: Next.js firebase.ts 설계 기준
- 필수 학습 · Firebase Authentication 사용 기준: 로그인 유지와 비밀번호 재설정
- 필수 학습 · Firebase 보안 규칙 설계: Firestore와 Storage 권한 관리하기
- 필수 학습 · Firestore CRUD 사용법: 컬렉션 구조와 읽기 쓰기 흐름
- 필수 학습 · Firebase Auth Context 설계: 로그인 권한과 라우팅 관리하기
- 필수 학습 · Firebase Storage 이미지 업로드 사용법: 상품 이미지 관리 흐름 만들기
- 필수 학습 · Firebase Custom Claims 사용법: 관리자 권한 구분하기
- 필수 학습 · Firebase Functions v2 사용법: 트리거 배포 Secret 처리
- 필수 학습 · Firestore seed data 설계: 리뷰 더미 데이터 구조 잡기
- 선택 참고 · Firebase 배포 제외 파일 설정: firebase.json의 ignore 사용법
- 선택 참고 · Firebase Firestore 인덱스 삭제 질문 해결: 배포 중 안전하게 판단하기
- 선택 참고 · Firebase Auth unauthorized-domain 오류 해결: 로그인 도메인 설정 확인
- 선택 참고 · Firebase permission-denied 오류 해결: Firestore Rules 체크리스트
- 선택 참고 · Firebase Storage 이미지 오류 해결: 403·404·token·Rules 확인법
- 선택 참고 · Firebase CORS 오류 해결: Storage 이미지 업로드가 막힐 때 확인할 설정
- 필수 선수 · Firebase 실무 오류 해결 모음: Storage, Firestore, Auth 체크리스트
- 필수 학습 · Firestore undefined 오류 해결: 선택 필드가 저장을 막을 때 현재 글
- 필수 학습 · Firestore arrayUnion 중첩 배열 오류: 배열을 그대로 넘기면 실패하는 이유
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.