연구 노트EthiLab

에러 메시지가 진짜 원인을 가리고 있었다

KeyError로 죽길래 데이터 형식 문제인 줄 알았다. 실제로는 로그아웃 응답을 받고 있었다.
📅 2026.08.05⏱ 읽기 약 5
EthiLab알고리즘 시그널 연구소실시간 스윙 트레이딩 시그널을 웹에서 확인하세요바로가기 →

하루에 세 번 죽은 배치

매일 장 마감 후 도는 배치가 하루에 세 번 연속 실패했다. 재실행해도 같은 자리에서 멈췄다.

에러는 명확해 보였다.

KeyError: '지수명'

지수 데이터를 가져와 컬럼을 읽는 부분이었다. 지수명이라는 컬럼이 없다는 뜻이니, 데이터 제공처가 컬럼명을 바꿨거나 응답 형식이 달라졌다고 생각했다. 실제로 이런 일은 흔하다.

앞 단계는 멀쩡했다

그런데 이상한 점이 있었다. 배치는 여섯 단계로 나뉘는데, 지수를 읽는 6단계에서만 죽었다. 앞의 1~5단계는 955개 종목 데이터를 정상적으로 가져왔다. 같은 제공처, 같은 라이브러리였다.

로그인도 성공한 상태였다. 인증이 만료됐다면 앞 단계부터 실패했어야 한다.

컬럼명이 바뀐 거라면 왜 이 함수만 영향을 받을까. 형식이 달라진 거라면 왜 다른 조회는 멀쩡할까. 에러 메시지가 가리키는 방향과 실제 증상이 맞지 않았다.

응답 본문을 직접 열어봤다

라이브러리를 거치지 않고 원본 응답을 그대로 받아봤다. 돌아온 것은 JSON이 아니었다.

LOGOUT

데이터가 아니라 로그아웃 안내였다. 세션이 끊긴 상태에서 조회를 요청했고, 서버는 데이터 대신 그 사실을 알려준 것이다.

그러면 왜 KeyError가 났을까. 라이브러리가 응답을 파싱하다 실패하면 예외를 던지지 않고 빈 DataFrame을 반환하는 구조였다. 호출한 쪽은 정상 데이터를 받았다고 믿고 컬럼을 읽으려 하고, 그 순간 KeyError가 난다.

즉 내가 본 에러는 원인이 아니라 한 단계 뒤의 증상이었다. 진짜 사건은 그 전에 조용히 일어났고, 예외가 삼켜지면서 흔적이 남지 않았다.

찾아보니 같은 지적이 상류 저장소 이슈로 1년 넘게 열려 있었다. 알려진 동작이지만 고쳐지지 않은 상태였다.

왜 하필 그 조회만

한 가지는 끝까지 확정하지 못했다. 같은 세션으로 앞 단계는 성공하는데 지수 조회만 거부당하는 이유다.

가능성은 몇 가지 떠올랐다. 실행 환경의 IP 대역이 차단됐거나, 조회 종류별로 세션 유지 방식이 다르거나, 서버 쪽 부하 정책일 수도 있다. 어느 쪽인지 가리려면 다른 환경에서 같은 계정으로 실행해 비교해야 하는데, 지금 그 계정 정보는 실행 환경에만 있고 로컬에는 없다.

가리지 못한 채로 두는 편을 택했다. 배치는 매일 돌아야 하고, 원인 규명을 기다리는 동안 데이터가 계속 비기 때문이다.

조회 하나만 갈아끼웠다

지수 데이터만 다른 제공처로 바꿨다. 종목 목록·시가총액·수급 등 나머지 조회는 그대로 뒀다. 전체를 옮기면 검증할 면적이 커지고, 지금 문제를 일으키는 건 지수 하나였다.

교체 후 실행한 배치는 32분 만에 정상 종료했다. 평소 성공 패턴과 같은 소요 시간이었다.

💡 남은 위험은 그대로다. 원래 제공처에 의존하는 조회가 아직 여럿 있고, 오늘 그것들이 정상 작동한 것은 운이 좋았을 뿐일 수 있다. 대체 경로를 준비해두는 일이 다음 과제로 남았다.

배운 것

에러 메시지는 사건이 일어난 지점이 아니라 결과가 드러난 지점을 가리킨다. 특히 중간 계층이 예외를 삼키고 빈 값을 돌려주는 구조에서는, 처음 보이는 에러가 진짜 원인에서 한참 떨어져 있다.

이번에는 "앞 단계는 멀쩡한데 왜 이것만"이라는 어긋남이 단서였다. 에러 메시지를 그대로 믿고 컬럼명부터 뒤졌다면 한참을 헤맸을 것이다. 메시지가 말하는 것과 증상의 모양이 맞지 않으면, 메시지를 의심하고 원본 응답을 직접 열어보는 편이 빠르다.