/개발/UnicodeDecodeError 'utf-8' codec can't decode byte 해결 (cp949·euc-kr)
개발UnicodeDecodeErrorpython 인코딩 에러

UnicodeDecodeError 'utf-8' codec can't decode byte 해결 (cp949·euc-kr)

UnicodeDecodeError 'utf-8' codec can't decode byte 에러를 추측 없이 해결하는 법. charset_normalizer 진단부터 open·pandas read_csv·requests·subprocess 상황별 복붙 코드와 cp949/euc-kr 한글 깨짐, errors=ignore·replace 차이까지 정리했습니다.

UnicodeDecodeError 'utf-8' codec can't decode byte 해결 (cp949·euc-kr)

UnicodeDecodeError 'utf-8' codec can't decode byte 완벽 해결 (cp949·euc-kr)

파이썬 개발 가이드 3편

CODE
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xec in position 0

이 에러 메시지를 그대로 복사해서 검색창에 친 분, 잘 오셨습니다. 결론부터 말하면 encoding을 추측으로 바꿔 끼우지 마세요. utf-8cp949euc-krlatin1을 차례로 갈아 끼우다 보면 운 좋게 한 번은 읽히지만, 그건 "왜 됐는지 모르는 상태"라서 다음 파일에서 또 막힙니다. 이 글은 (1) 실제 인코딩을 한 줄로 진단 → (2) byte 값·position으로 원인 분류 → (3) 상황별 복붙 코드로 끝내는 방식입니다.

1단계: 추측 금지, 실제 인코딩부터 확인하세요

일단 이걸 쳐보세요. 터미널에서 파일 경로만 바꾸면 됩니다.

Bash
# charset-normalizer (요즘 사실상 표준, chardet보다 빠름)
pip install charset-normalizer
python -m charset_normalizer your_file.csv

스크립트 안에서 쓰고 싶다면:

Python
from charset_normalizer import from_path
result = from_path("your_file.csv").best()
print(result.encoding)   # 예: 'cp949', 'utf_8', 'euc_kr'

# (구버전 chardet을 쓴다면)
import chardet
with open("your_file.csv", "rb") as f:
    print(chardet.detect(f.read()))
    # {'encoding': 'EUC-KR', 'confidence': 0.99, ...}

진단 결과가 나오면 그 인코딩을 encoding=에 그대로 넣으면 끝입니다. 그래도 감을 잡고 싶다면, 에러 메시지의 byte 값으로도 대략 분류할 수 있습니다.

byte 값·position 원인 분류표

에러의 byte 값추정 실제 인코딩상황
0xec, 0xed, 0xeaUTF-8로 인코딩된 한글파일은 정상 UTF-8인데 읽는 쪽 코드가 엉뚱한 코덱일 때
0xb0~0xc8 대 (예 0xb0, 0xc7)cp949 / euc-kr 한글윈도우 메모장·엑셀·레거시 시스템이 만든 한글 파일
0xef 0xbb 0xbf (position 0)UTF-8 BOM엑셀이 "CSV UTF-8"로 저장한 파일
0xff 0xfe / 0xfe 0xffUTF-16 (LE/BOM)메모장 "유니코드" 저장
0x80~0xff 단독, position이 들쭉날쭉혼합 인코딩 의심여러 소스가 합쳐진 로그·CSV

position 0에서 터지면 파일 맨 앞 글자/BOM 문제라 진단이 쉽고, position이 큰 숫자면 앞부분은 ASCII(영문)라 멀쩡히 읽히다가 첫 한글에서 깨진 케이스입니다.

2단계: 상황별 복붙 해결 코드 4종

진단으로 알아낸 인코딩을 각 상황에 맞게 명시해줍니다.

① 일반 파일 읽기 — open()

Python
# ❌ Before: encoding 미지정 → OS 기본값(윈도우=cp949)에 의존
with open("data.txt") as f:
    text = f.read()   # UnicodeDecodeError 발생

# ✅ After: encoding을 명시
with open("data.txt", encoding="cp949") as f:   # 또는 "utf-8"
    text = f.read()

② pandas read_csv

Python
import pandas as pd

# ❌ Before
df = pd.read_csv("sales.csv")   # 'utf-8' codec can't decode byte 0xb0 ...

# ✅ After: 엑셀이 만든 한글 CSV는 보통 cp949
df = pd.read_csv("sales.csv", encoding="cp949")

# ✅ "CSV UTF-8(쉼표로 분리)"로 저장한 파일 → BOM 제거
df = pd.read_csv("sales.csv", encoding="utf-8-sig")

💡 엑셀 한글 CSV는 십중팔구 cp949, 엑셀에서 "CSV UTF-8" 옵션으로 저장했다면 utf-8-sig입니다.

③ subprocess

Python
import subprocess

# ❌ Before: bytes로 받아 디코딩 시 깨짐
out = subprocess.run(["git", "log"], capture_output=True).stdout
# out.decode()  # 윈도우 한글 출력에서 에러

# ✅ After: text=True + encoding 명시
out = subprocess.run(
    ["git", "log"],
    capture_output=True,
    text=True,
    encoding="utf-8",   # 윈도우 콘솔 출력이면 "cp949"가 맞을 때도 많음
).stdout

④ requests 웹 응답

Python
import requests
r = requests.get("https://example.co.kr/legacy.html")

# 케이스 A: 서버가 euc-kr인데 헤더가 부실해 requests가 잘못 추측
text = r.content.decode("euc-kr")   # bytes를 직접 디코딩

# 케이스 B: r.text를 쓰고 싶으면 인코딩을 강제 지정
r.encoding = "utf-8"   # 이 줄 이후 r.text가 올바르게 디코딩됨
text = r.text

r.textr.encoding 값으로 디코딩하므로, 헤더 추측이 틀렸으면 r.encoding을 먼저 고정하거나 r.content를 직접 디코딩하는 게 안전합니다.

3단계: 그래도 안 될 때 — errors 옵션과 BOM

진짜 인코딩을 모르거나, 한 파일에 인코딩이 섞여 있을 때 임시로 쓰는 옵션입니다. 데이터 손실 위험을 반드시 이해하고 쓰세요.

Python
with open("dirty.txt", encoding="utf-8", errors="replace") as f:
    text = f.read()

errors 옵션 비교표

옵션동작깨진 byte 출력 예위험도
strict (기본)예외 발생UnicodeDecodeError안전(읽기 실패)
ignore디코딩 불가 문자를 삭제한글 (글자 사라짐)⚠️ 데이터 손실, 복구 불가
replace(U+FFFD)로 치환한�글⚠️ 원본 추적 불가
backslashreplace원본 byte를 \x..로 표시한\xeb글손실은 없으나 사람이 읽기 어려움

핵심 경고: errors="ignore"는 "에러는 안 나니까 됐다"가 아니라 글자가 조용히 사라지는 가장 위험한 옵션입니다. 금액·수량 같은 데이터를 다룬다면 절대 쓰지 마세요. 디버깅 중 byte 위치를 확인하고 싶을 때만 backslashreplace를 잠깐 쓰는 정도가 적절합니다.

BOM(0xef 0xbb 0xbf) 처리

position 0에서 \ufeff 같은 보이지 않는 문자가 첫 컬럼명에 붙어 KeyError가 난다면 BOM입니다. utf-8 대신 utf-8-sig로 읽으면 자동으로 제거됩니다.

Python
with open("excel_export.csv", encoding="utf-8-sig") as f:
    ...

실무 한마디

저는 신규 파이프라인을 짤 때 무조건 첫 줄에 python -m charset_normalizer를 돌려 인코딩을 로그로 남깁니다. 운영 환경에서 "어제까지 되던 배치가 갑자기 깨진" 사고의 8할은 데이터 공급처가 UTF-8→cp949(혹은 그 반대)로 저장 방식을 바꿨기 때문입니다. 진단을 자동화해두면 원인 파악이 5분 → 5초로 줄어듭니다.

윈도우 환경 팁 (PEP 686, PYTHONUTF8)

Python은 PEP 686에 따라 3.15부터 UTF-8 모드 기본화가 진행 중입니다. 그 전이라도 윈도우에서 cp949 기본값에 시달린다면 환경변수로 강제할 수 있습니다.

Bash
# 윈도우(PowerShell)
$env:PYTHONUTF8 = "1"
python app.py

# 또는 실행 시 옵션
python -X utf8 app.py

이러면 open()의 기본 encoding이 UTF-8이 됩니다. 단, cp949 파일을 읽는 코드라면 여전히 encoding="cp949"를 명시해야 합니다. 기본값을 바꿔도 파일 자체의 인코딩은 바뀌지 않으니까요.

결론: 진단 → 해결 3단계 체크리스트

  1. 진단: python -m charset_normalizer 파일명으로 실제 인코딩 확인 (추측 금지)
  2. 분류: 에러의 byte 값으로 원인 짐작 — 0xec대=UTF-8 한글, 0xb0~0xc8대=cp949/euc-kr, 0xef bb bf=BOM
  3. 해결: open(encoding=) / read_csv(encoding="cp949"|"utf-8-sig") / subprocess(text=True, encoding=) / requestsr.content.decode() 또는 r.encoding 지정

errors="ignore"는 마지막 수단도 아닙니다. 데이터가 사라지니 피하세요.

자주 묻는 질문 (FAQ)

Q. 윈도우 메모장으로 저장한 한글 txt가 안 읽혀요. A. 메모장 기본 저장이 cp949(ANSI)인 경우가 많습니다. open("f.txt", encoding="cp949")로 읽으세요. 메모장에서 "다른 이름으로 저장 → 인코딩: UTF-8"로 다시 저장하면 이후 utf-8로 통일됩니다.

Q. 엑셀에서 만든 CSV의 한글이 pandas에서 깨집니다. A. 엑셀 한글 CSV는 보통 encoding="cp949"입니다. "CSV UTF-8(쉼표로 분리)" 형식으로 저장했다면 encoding="utf-8-sig"를 쓰면 BOM까지 함께 처리됩니다.

Q. euc-kr 레거시 파일과 utf-8 파일이 섞여 있어요. 한 번에 처리할 방법은? A. 파일별로 charset_normalizer로 인코딩을 먼저 감지한 뒤 그 값으로 열도록 자동화하세요. 한 파일 안에 인코딩이 섞였다면 errors="backslashreplace"로 깨진 byte 위치를 찾아 원본 공급처에 인코딩 통일을 요청하는 것이 정석입니다.


다음 편 예고 — 4편: Python 가상환경·패키지 설치 후 자주 터지는 SSL/인증서 에러 트러블슈팅

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 자료 조사와 1차 초안 작성을 담당하고, 사람 편집자가 사실관계·출처·톤과 맥락을 검토한 뒤 발행했습니다. 환경(OS·버전)에 따라 결과가 다를 수 있으니 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

초안 · AI (Content Reviewer)·검토 · Nodelog 편집자·발행 ·
관련 공식 문서Python 공식 문서

댓글

첫 번째 댓글을 남겨보세요.