YAML 함정 5가지 — NO가 false가 되는 Norway Problem부터 탭 들여쓰기까지

쿠버네티스 클러스터에서 노르웨이 사용자 데이터가 모두 사라졌습니다. DB는 멀쩡했고 쿼리도 이상 없었습니다. 범인은 설정 파일 한 줄이었습니다.

country: NO

YAML 1.1에서 NO는 불리언 false입니다. 노르웨이 국가코드가 조용히 false로 바뀌어 저장된 것입니다. 이것이 유명한 Norway Problem입니다.

하지만 이건 YAML 함정의 시작일 뿐입니다. 운영 환경을 조용히 망가뜨리는 함정 5가지를 정리합니다.


직접 테스트하기

YAML 변환기 열기 →
YAML을 붙여넣으면 JSON·TOML 변환과 함께 아래 함정들을 실시간으로 감지합니다

1. Norway Problem — yes/no/on/off가 불리언으로

YAML 1.1은 대소문자 무관하게 다음 값들을 불리언으로 처리합니다.

true로 파싱false로 파싱
true, True, TRUEfalse, False, FALSE
yes, Yes, YES, yEs (모든 대소문자)no, No, NO, nO (모든 대소문자)
on, On, ONoff, Off, OFF

실제로 이 문제를 만나는 상황:

  • 국가코드: NO (노르웨이), ON (온타리오주)
  • 설문 답변: response: Y, answer: N
  • 피처 플래그: logging: off, cache: on

해결: 따옴표로 감싸기

country: "NO"    # 문자열 — 정확
logging: "off"   # 문자열 — 정확
logging: off     # false — 의도와 다를 수 있음

2. 앞에 0이 붙으면 8진수 (01234 ≠ 1234)

YAML 1.1은 C 언어 규칙을 따릅니다. 앞에 0이 붙은 숫자는 8진수로 처리됩니다.

zipcode: 01234    # → 668 (10진수 변환)
zipcode: "01234"  # → "01234" (문자열)

함정을 만나는 상황:

  • 우편번호: 미국·한국 일부 코드가 0으로 시작
  • 상품코드/SKU: 0123은 83
  • 계좌번호: 거의 항상 문자열로 처리해야 함
  • 전화번호: 0101234567 → 8진수 오류

해결: 0으로 시작하는 식별자는 항상 따옴표


3. 콜론이 있으면 60진수 (1:30 → 90)

YAML 1.1은 시간 표기를 위해 60진법 숫자를 지원합니다.

duration: 1:30      # → 90 (1×60 + 30)
duration: 3:00:00   # → 10800 (3×3600)

함정을 만나는 상황:

  • 타임아웃 설정: timeout: 1:30 → 90초가 아닌 90
  • 포트 매핑: mapping: 80:443 → 일부 파서에서 숫자 변환
  • 버전 문자열: version: 1:2.3

YAML 1.2와 최신 go-yaml(Kubernetes 사용)은 60진수를 지원하지 않지만, 레거시 설정 파일을 다룬다면 따옴표가 유일한 안전책입니다.

해결:

duration: "1:30"

4. 탭 들여쓰기 금지

Python과 달리 YAML은 들여쓰기에 탭을 명시적으로 금지합니다. 파서가 오류를 내거나 구조를 잘못 해석합니다.

server:
→ host: localhost    # ← 탭 = 파싱 오류
  port: 8080

특히 문제가 되는 상황:

  • 탭은 에디터에서 눈에 보이지 않음
  • Slack·이메일·PDF에서 복붙할 때 스페이스가 탭으로 변환
  • IntelliJ, 구버전 VS Code가 기본으로 탭 삽입

YAML 주석과 함께 들여쓰기 가이드를 파일 상단에 남기는 습관도 좋습니다:

# 들여쓰기: 스페이스 2칸 (탭 금지)
# 문자열 값은 따옴표 사용 권장
server:
  host: localhost
  port: 8080

해결: 에디터에서 탭 → 스페이스 자동 변환 설정. 탭 포함 확인:

grep -Pn '^\t' config.yaml

5. 숫자처럼 생긴 문자열이 자동 변환

YAML은 타입 추론을 적극적으로 합니다. 따옴표 없이 숫자처럼 생긴 값은 모두 변환됩니다.

version: 1.0          # → 1.0 (float) — "1.0" 문자열을 원했는데
date: 2026-04-18      # → Date 객체 (많은 파서에서)
port: 8080            # → 8080 (정수)
phone: 0101234567     # → 8진수 오류 가능

왜 문제냐: version: 1.0은 float이 되어서 JSON 직렬화 시 "version": 1로 소수점이 사라지고, version == "1.0" 비교가 실패합니다.

해결: 문자열이어야 하는 값은 항상 따옴표

version: "1.0"
date: "2026-04-18"
phone: "0101234567"

가장 안전한 규칙 하나

의미상 문자열이어야 하는 값은 무조건 따옴표. 따옴표 두 개의 비용은 0이고, 조용한 타입 오류의 디버깅 비용은 몇 시간입니다.

# ✓ 안전
country: "NO"
zipcode: "01234"
duration: "1:30"
version: "1.0"

# ✗ 나중에 터질 수 있음
country: NO
zipcode: 01234
duration: 1:30
version: 1.0

자동으로 잡아내기

iTool YAML ↔ JSON ↔ TOML 변환기는 위 5가지 함정을 입력과 동시에 실시간으로 감지하고 경고를 표시합니다. Norway Problem, 8진수, 60진수, 탭 들여쓰기, 자동 타입 변환 모두 커버합니다.

자주 묻는 질문

YAML에서 NO가 왜 false로 변환되나요?

YAML 1.1 스펙은 yes/no/on/off를 대소문자 관계없이 불리언으로 처리합니다. 노르웨이 국가코드 NO는 false로 파싱됩니다. 반드시 따옴표로 감싸야 합니다: country: "NO"

YAML에서 주석은 어떻게 작성하나요?

# 기호로 시작합니다. 줄 중간에도 사용 가능합니다: host: localhost # 로컬 개발용. 단, 따옴표 안의 # 기호는 주석이 아닌 문자열로 처리됩니다.

앞에 0이 붙은 숫자(우편번호 등)를 YAML에 쓰려면?

반드시 따옴표로 감싸야 합니다. 예: zipcode: "01234". 따옴표 없이 쓰면 YAML 1.1이 8진수로 해석해 01234가 668이 됩니다.

YAML 1.2로 업그레이드하면 Norway Problem이 해결되나요?

YAML 1.2는 true/false만 불리언으로 처리해 yes/no/on/off 문제가 없어집니다. 하지만 Kubernetes 등 많은 도구가 여전히 YAML 1.1 파서를 사용하므로 따옴표 습관이 가장 안전합니다.

YAML 탭 들여쓰기는 왜 오류가 나나요?

YAML 스펙이 들여쓰기에 탭을 명시적으로 금지하기 때문입니다. 스페이스 2칸 또는 4칸을 일관되게 사용해야 합니다. 에디터에서 탭을 스페이스로 자동 변환하도록 설정하세요.