티스토리 뷰
목차
폰에서 자동화 봇에게 말을 걸었는데 401 오류만 돌아왔습니다.
그런데 같은 시각, 크론이 새벽에 만든 글은 이미 멀쩡히 올라와 있었습니다.

봇은 401인데, 자동 발행은 왜 멀쩡했을까
저는 VPS 한 대에서 텔레그램 봇 여러 개와 새벽 자동 발행 파이프라인을 같이 돌립니다.
둘 다 같은 방식으로 인증합니다. 로그인 토큰 파일을 읽어서, 그 토큰으로 claude를 호출하는 구조입니다.
그래서 토큰이 죽었다면 봇도, 새벽 발행도 똑같이 죽어야 정상입니다.
그런데 제 VPS에서는 봇에 말을 걸 때만 401이 떴고, 크론이 돌린 새벽 발행은 몇 번을 확인해도 멀쩡했습니다.
같은 토큰 파일을 보는 두 프로그램인데, 하나는 아프고 하나는 멀쩡한 상황이었습니다.
재인증부터 했는데, 똑같았다
이런 상황에서 제일 먼저 드는 생각은 "토큰이 또 만료됐나"였습니다.
그래서 재인증 절차부터 밟았습니다. 로그인 창이 뜨는 스크립트를 실행하고, 새 주소로 로그인하고, 나온 코드를 다시 넣었습니다.
재인증은 매번 성공으로 끝났습니다. 그런데 봇에게 다시 말을 걸어보면 여전히 401이었습니다.
한 번도 아니고 여러 번 반복됐습니다. 팀 운영 문서에는 이 실수를 이렇게 못 박아 놓은 문장이 남아 있습니다.
| 운영 문서에 남은 문구 |
|---|
| "폰 봇만 401이고 크론은 멀쩡하면 토큰 취소가 아니라 데몬 미재시작이다(2026-08-16 오진 사례) — 재인증 말고 systemctl restart tg-*." |
이 문장이 문서에 박혀 있다는 것 자체가, 처음엔 저도 이 문제를 "토큰이 취소됐다"로 오진하고 재인증부터 했다는 증거입니다.
재인증은 틀린 처방이 아니었습니다. 다만 그 처방이 필요한 곳에 닿지 못했을 뿐입니다.
원인은 코드 한 줄에 있었다

관제 스크립트(ops_doctor.py) 코드를 열어보니, 이 상황을 정확히 짚어주는 함수가 이미 있었습니다.
def _stale_token(unit: str, file_token: str) -> bool:
"""systemd는 EnvironmentFile을 데몬이 기동될 때만 읽는다.
재인증 뒤 재시작이 빠지면 데몬은 취소된 옛 토큰으로
claude를 불러 401만 낸다."""
pid = subprocess.run(
["systemctl", "show", "-p", "MainPID", "--value", unit],
capture_output=True, text=True).stdout.strip()
...
env = Path(f"/proc/{pid}/environ").read_bytes().split(b"\0")
for kv in env:
if kv.startswith(TOKEN_KEY.encode() + b"="):
return kv.split(b"=", 1)[1].decode(errors="replace") != file_token
return False
핵심은 함수 이름 그대로 "stale"(묵은) 토큰 여부를 판정한다는 점입니다.
텔레그램 봇 같은 상주 데몬은 systemd로 떠 있습니다. systemd는 EnvironmentFile(토큰이 든 환경변수 파일)을 딱 한 번, 데몬이 기동될 때만 읽습니다.
재인증으로 토큰 파일 내용이 바뀌어도, 이미 떠 있는 데몬의 메모리 속 토큰은 그대로입니다.
재시작을 해줘야 그때 파일을 다시 읽고 새 토큰을 가져갑니다. 재시작이 빠지면 데몬은 취소된 옛 토큰으로 계속 claude를 호출하고, 그 결과가 매번 401입니다.
반대로 크론이 새벽마다 새로 띄우는 발행 프로세스는 실행될 때마다 토큰 파일을 처음부터 다시 읽습니다.
그래서 재인증 직후라도 크론 쪽은 항상 최신 토큰을 물고 시작합니다. 봇과 크론이 다르게 반응한 이유가 바로 이 "언제 읽느냐"의 차이였습니다.
| 구분 | 토큰을 언제 읽나 | 재인증 직후 상태 |
|---|---|---|
| 상주 데몬(텔레그램 봇 등, systemd) | 기동될 때 딱 1번 | 재시작 전까지 옛 토큰 그대로 — 401 |
| 크론이 매번 새로 띄우는 프로세스(새벽 자동 발행 등) | 실행될 때마다 새로 | 항상 최신 토큰 — 정상 |
이 함수 docstring에는 실제로 있었던 사례 수치도 같이 적혀 있었습니다.
08월 3일 기동한 텔레그램 봇 계열 데몬 7개와 발행 관련 데몬 1개가, 08월 9일과 08월 16일 두 차례나 재인증을 거치고도 정작 재시작은 되지 않아 08월 17일까지 옛 토큰을 그대로 물고 있었다는 기록입니다.
| 시점 | 무슨 일이 있었나 | 데몬 상태 |
|---|---|---|
| 08-03 | 봇 계열 데몬 7개 + 발행 관련 데몬 1개 기동 | 이 시점 토큰은 정상 |
| 08-09 | 토큰 재인증 실행 | 재시작 누락 — 메모리엔 여전히 옛 토큰 |
| 08-16 | 다시 토큰 재인증 실행 | 이번에도 재시작 누락, 옛 토큰 유지 |
| ~08-17 | 문제를 알아채고 정리할 때까지 | 그 사이 폰으로 넣은 봇 주문이 전부 401로 실패 |
재인증을 두 번이나 했는데도 문제가 안 풀렸던 진짜 이유가, 이 표 안에 그대로 있었습니다.
토큰은 멀쩡했습니다. 다만 그 토큰을 쓸 프로세스가 한 번도 새로 시작되지 않았을 뿐입니다.
해결: 재인증 다음엔 반드시 재시작

해결 자체는 명령 한 줄이었습니다. 텔레그램 봇 계열 데몬을 재시작하자 그 즉시 정상으로 돌아왔습니다.
문제는 "재시작 한 줄"을 매번 사람이 기억해야 한다는 점이었습니다. 사람은 잊어버립니다. 이번에도 두 번이나 잊고 재인증만 반복했습니다.
그래서 관제 스크립트 쪽에 점검 로직을 하나 더 넣었습니다.
정기 점검 때마다 살아있는 데몬의 메모리 속 토큰과, 토큰 파일에 지금 적힌 값을 비교합니다. 둘이 다르면 재인증 후 재시작을 깜빡한 상태라는 뜻이므로, 그 데몬을 자동으로 재시작합니다.
이제는 재인증을 하고 재시작을 잊어도, 다음 정기 점검 때 자동으로 복구됩니다.
사람이 챙겨야 할 일을 하나 줄인 셈입니다.
비슷한 증상을 겪는다면 이 순서로 확인해보세요
① 인증 오류가 특정 프로그램에서만 뜨고 다른 자동화는 멀쩡한지부터 구분합니다. 전부 죽었다면 토큰 자체 문제, 일부만 죽었다면 아래로 넘어갑니다.
② 멀쩡한 쪽이 "실행할 때마다 새 프로세스를 띄우는 방식"(크론 등)이고, 안 되는 쪽이 "한 번 떠서 계속 살아있는 방식"(상주 데몬)인지 확인합니다.
③ 맞다면 토큰이 아니라 상주 데몬의 재시작 누락을 의심합니다. 재인증을 반복하지 말고 해당 데몬을 재시작해봅니다.
④ 재발 방지: 재인증 스크립트나 주기 점검 스크립트에 "관련 데몬 자동 재시작" 단계를 아예 넣어버리면, 이 오진을 다시 반복하지 않습니다.
이번 사고도 처음엔 겉보기엔 멀쩡해 보이는데 실제로는 멈춰 있던 경우였습니다. 새벽 배치가 질문만 던지고 조용히 멈춰버렸던 자동화 시스템 오류 사고 글도 "티 나지 않는 고장"이라는 점에서 같은 계열이었습니다.
토큰을 다루는 다른 자동화 이야기가 궁금하다면, 클로드 API 요금 정책이 예고 없이 바뀌었던 클로드 소네트5 API 가격 글도 함께 보면 운영 관점에서 참고가 됩니다. 잠금 포트 하나 때문에 크론이 통째로 조용히 멈췄던 포트 충돌 자동화 사고 글도 같은 무인 운영 기록 시리즈입니다.
FAQ
Q1. 텔레그램 봇에서 401 오류가 뜨는데 왜 다른 자동화는 멀쩡한가요?
그 자동화가 상주 데몬인지, 크론이 매번 새로 띄우는 프로세스인지에 달려 있습니다. 상주 데몬은 기동할 때 읽은 토큰을 재시작 전까지 그대로 씁니다. 크론이 새로 띄우는 프로세스는 실행될 때마다 토큰 파일을 다시 읽습니다.
Q2. 재인증을 했는데도 봇이 안 고쳐지면 뭘 먼저 봐야 하나요?
먼저 토큰 파일 자체가 실제로 갱신됐는지 확인하고, 그다음 그 토큰을 쓰는 상주 프로세스를 재시작했는지 확인합니다. 재인증과 재시작은 서로 다른 단계이고, 둘 다 해야 끝납니다.
Q3. 매번 재시작을 사람이 챙겨야 하나요?
사람이 챙기면 잊어버립니다. 이번에도 두 번이나 그랬습니다. 재인증 스크립트나 주기 점검 스크립트에 재시작 로직을 넣어 자동으로 처리하는 편이 안전합니다.
Q4. systemd가 아닌 다른 방식(도커 등)도 같은 문제가 생기나요?
원리는 같습니다. 프로세스가 시작될 때 환경변수를 한 번만 읽는 구조라면, 토큰 파일을 갱신해도 이미 실행 중인 프로세스에는 반영되지 않습니다. 컨테이너라면 재시작하거나 다시 배포해야 새 토큰이 적용됩니다.