증상: 코드도 데이터도 맞는데 결과가 비거나, 검사기와 폴백이 오류 없이 한 번도 돌지 않습니다.
원인: except pass 가 블록 전체를 삼키거나, % 포매팅이 문구 속 %에 죽거나, 잘라 낸 오류 문자열로 판별하거나, 형식 문자열의 자리와 값이 어긋났습니다.
해결: 예외를 잠깐 드러내 보고, %% 나 f-string 을 쓰고, 판별은 자르기 전 전문으로 하고, 일부러 실패시키는 시험으로 확인합니다.
파이썬에서 가장 찾기 어려운 버그는 예외가 나지 않는 버그입니다. 아래 네 가지는 모두 실제로 겪은 것이고, 공통점은 "잘 돌고 있는 것처럼 보였다"는 것입니다.
넷 다 겉으로는 정상이었다
| 증상 | 숨은 원인 | 드러난 오류 |
|---|---|---|
8개 칸을 담는 결과가 전부 빈 {} |
except Exception: pass |
TypeError("'int' object is not iterable") |
| 이미지 검사기가 하루 종일 꺼진 채 지나감 | 문구 속 "N% 할인"의 % | not enough arguments for format string |
| 넣어 둔 폴백이 한 번도 안 돎 | 오류 문자열을 앞 300자로 자른 뒤 판별 | 판별기가 항상 False |
| 새 항목에 옆 항목의 빈 배열이 들어감 | 형식 문자열의 자리와 값 위치가 다름 | 오류 없음 |
1. except pass 는 한 줄의 실패로 블록 전체를 지운다
파일에서 8개 칸을 읽어 사전에 담는 코드가 전부 빈 값을 냈습니다. 같은 파일을 따로 파싱하면 성공했습니다. 예외를 드러내 보니 일부 파일에서 한 칸이 list 가 아니라 int 였고, 그 칸을 돌다 터진 예외를 except: pass 가 삼켜 8개 칸이 모두 날아간 것이었습니다.
try:
issues = data.get("issues")
detail["issues"] = list(issues) if isinstance(issues, list) else []
except Exception as e:
print(f"detail 실패: {e!r}", file=sys.stderr)
외부 JSON 은 isinstance 로 막고, 삼켜야 할 때도 stderr 에 한 줄은 남깁니다. 결과가 이상하게 비면 먼저 except 를 잠깐 드러내 봅니다. 같은 형식의 파일이라도 만든 시점에 따라 칸의 자료형이 다를 수 있다는 점도 이때 알았습니다.
2. % 포매팅 문자열 안의 %
검사용 문구에 "N% 할인" 을 넣었더니 그 문자열이 "..." % path 형식이라 %가 지시자로 읽혀 모든 호출이 죽었습니다. 예외는 경고로만 처리되어 하루 종일 아무도 몰랐습니다.
prompt = "N%% 할인 문구가 있는지 보라: %s" % path # %% 로 이스케이프
prompt = f"N% 할인 문구가 있는지 보라: {path}" # f-string 이면 걱정 없음
오류 문구는 % 뒤에 어떤 글자가 오느냐에 따라 달라집니다. 당시에는 위 표의 문구가 났고, 이스케이프 없이 "N% 할인" 을 그대로 넣어 다시 돌려 보니 unsupported format character 가 났습니다. 어느 쪽이든 원인과 고치는 법은 같습니다.
3. 잘라 낸 오류 문자열로 판별하기
모델이 지원되지 않으면 다음 모델로 넘어가는 폴백을 넣었는데, 오류를 stderr[:300] 으로 자른 뒤 "not supported" 를 찾았습니다. 그 CLI 는 stderr 앞부분에 버전과 설정 같은 배너를 찍어서, 정작 오류 문구가 300자 안에 들어오지 않았습니다.
err_full = (proc.stdout or "") + (proc.stderr or "")
unsupported = "not supported" in err_full # 판별은 전문으로
log_excerpt = err_full.strip()[-300:] # 로그는 뒤쪽 300자
4. 형식 문자열에 항목을 끼울 때
여러 %s 를 채우는 문자열에 새 자리를 앞쪽에 넣고 값은 뒤쪽에 넣었더니, 새 항목에 옆 항목의 빈 배열이 들어갔습니다. 자리 개수만 맞으면 파이썬은 오류를 내지 않습니다. 자리와 값은 같은 편집에서 같은 위치에 넣습니다.
숨은 실패를 찾는 법
- 폴백은 일부러 실패시켜 봅니다. 첫 순위에 없는 모델 이름을 넣고 실제로 다음 순위로 넘어가는지 봤고, 이 시험으로 판별기가 늘 False 인 것을 찾았습니다.
- 문구를 고친 뒤에는 그 함수를 한 번 실제로 호출해 죽지 않는지 봅니다.
- 형식 문자열을 바꾼 직후에는 만들어진 값을 찍어 각 자리에 맞는 값이 들어갔는지 눈으로 봅니다.
조용한 실패는 관찰로 잡히지 않는다
네 경우 모두 결과물만 눈으로 봐서는 찾을 수 없었습니다. 검사기가 꺼진 채 통과한 결과물은 검사기가 돌고 나서 통과한 결과물과 똑같이 생겼기 때문입니다. 폴백도 첫 순위가 잘 되는 동안에는 쓸 일이 없으니, 죽어 있어도 아무 일이 없어 보입니다.
그래서 이런 장치를 넣거나 고친 직후에는 "나중에 지켜보자"로 미루지 않고, 그 자리에서 한 번 실제로 부르거나 일부러 실패시켜 봅니다. 코드가 들어간 것과 그 코드가 실제로 도는 것은 다른 사실이라는 점을 이 네 가지 일로 배웠습니다.
확인한 환경
| 항목 | 내용 |
|---|---|
| 언어 | 파이썬 3 |
| 관련 도구 | 외부 CLI 호출(subprocess), JSON 파일 읽기, 자바스크립트 데이터 파일 생성 |
관련 글
이 글의 내용은 2026년 10월 5일에 마지막으로 확인했습니다. 틀린 곳을 발견하시면 연락처로 알려 주세요.