사후 분석: 오래된 OAuth와 격리된 크론 작업으로 인한 Claude Max + OpenClaw 청구 오류

자체 호스팅 OpenClaw 설정과 Claude Max가 할당량을 초과하지 않았음에도 billing error — API key has run out of credits를 반환하기 시작했습니다. 이틀간의 디버깅 끝에 두 가지 근본 원인과 고장을 무작위로 보이게 하는 킬 체인이 밝혀졌습니다.
근본 원인 1: 오래된 OAuth 토큰이 전체 제공자를 오염시킴
auth-profiles.json에 두 개의 항목이 있었습니다: 유효한 anthropic:claude-cli OAuth 프로필과 sk-ant-oat01-... 토큰이 있는 anthropic:manual 프로필입니다. 수동 토큰이 만료되었을 때, OpenClaw는 해당 프로필만 실패 처리하지 않고 제공자 수준의 결제 실패로 분류하여 전체 anthropic 제공자를 블랙리스트에 등록하여, 정상 OAuth 프로필을 포함한 모든 모델을 건너뛰었습니다. 로그에는 다음이 표시되었습니다:
reason: "billing" errorPreview: "Provider anthropic has billing issue (skipping all models)" chain_exhausted
유효한 갱신 토큰이 있는 정상 OAuth 프로필은 시도조차 되지 않았습니다.
수정: auth-profiles.json와 openclaw.json에서 anthropic:manual을 완전히 제거합니다. anthropic:claude-cli만 유지합니다.
근본 원인 2: 격리된 cron 작업이 별도의 결제 버킷에 도달함
OpenClaw에는 두 가지 실행 경로가 있습니다:
- 메인 세션 —
/usr/bin/claude바이너리를 실행하며 Max/Pro 구독으로 청구됨 ✅ - 격리/내장 실행 — Anthropic API에 직접 HTTP 요청을 보내며 Extra Usage 버킷으로 청구됨 ❌
sessionTarget: isolated로 설정된 cron 작업은 독립형 내장 에이전트를 실행하며, 이는 CLI가 보내는 Claude Code 헤더 없이 Anthropic API에 직접 HTTP로 호출합니다. Anthropic은 이를 Extra Usage 버킷으로 라우팅하며, 이는 완전히 별도의 할당량입니다. Extra Usage가 꺼져 있으면 모든 격리된 cron 실행은 400을 반환합니다. OpenClaw는 상황을 악화시킵니다: 하나의 결제 오류가 auth-state.json에 disabledUntil을 약 24시간 앞으로 설정하여, 모든 요청(일반 채팅 포함)을 쿨다운이 발생할 때까지 잠급니다. 잠금은 게이트웨이 재시작 후에도 유지됩니다.
전체 킬 체인
- 게이트웨이 재시작 → 놓친 cron 작업이 따라잡기 위해 대기열에 추가됨
- 격리 에이전트가 내장 실행자로 실행 → Anthropic API에 직접 HTTP 호출(CLI 헤더 없음)
- Extra Usage 버킷 → 400 오류
- OpenClaw가 인증 프로필을 약 24시간 동안 잠금 → 모든 요청(일반 채팅 포함) 차단
수정 사항
- 결제 잠금 즉시 해제:
python3 -c " import json with open('/home/USER/.openclaw/agents/main/agent/auth-state.json') as f: d = json.load(f) if 'usageStats' in d: for profile in d['usageStats']: d['usageStats'][profile].pop('disabledUntil', None) d['usageStats'][profile].pop('failureCounts', None) d['usageStats'][profile].pop('errorCount', None) d['usageStats'][profile].pop('disabledReason', None) d['usageStats'][profile].pop('lastFailureAt', None) with open('/home/USER/.openclaw/agents/main/agent/auth-state.json', 'w') as f: json.dump(d, f, indent=2) print('해제 완료.') " openclaw gateway restart - 모든 cron 작업을
isolated에서main으로 이동:python3 -c " import json with open('/home/USER/.openclaw/cron/jobs.json') as f: d = json.load(f) jobs = d if isinstance(d, list) else d.get('jobs', []) for j in jobs: if j.get('sessionTarget') == 'isolated': print(f'수정 중: {j["name"]}') j['sessionTarget'] = 'main' with open('/home/USER/.openclaw/cron/jobs.json', 'w') as f: json.dump(d, f, indent=2) print('완료.') "
대상: 할당량을 초과하지 않았음에도 무작위 결제 오류가 발생하는 Claude Max 또는 Pro로 OpenClaw를 자체 호스팅하는 모든 사용자.
📖 전체 출처 읽기: r/openclaw
👀 See Also

OpenClaw 작업 공간 구성: 두 달 사용 후 얻은 교훈
OpenClaw 개발자의 경험에 따르면 작업 공간 품질이 에이전트 성능에 5-10배 영향을 미치며, SOUL.md, AGENTS.md, MEMORY.md, USER.md 및 스킬 구성에 대한 구체적인 지침이 제공됩니다.

MCP 서버 자체 설치하기: 세 가지 호스트, 세 가지 메커니즘, 주의사항
VS Code, Cursor, Claude Code에서 MCP 서버를 프로그래밍 방식으로 설치하는 방법 — API, 파일 쓰기, 잘못된 JSON, 원자적 쓰기, 멱등 업데이트 같은 예외 사례를 다룹니다.

특정 지침과 세부 조정으로 OpenClaw 설정을 최적화하는 방법
OpenClaw 최적화는 정확한 지시와 에이전트 개성의 지속적인 개선, 비용 효율적인 모델 활용에 의존합니다.

클로드 코드를 사용한 봇의 OAuth 토큰 자동 갱신
레딧 사용자가 OAuth 토큰 만료를 방지하는 방법을 공유했습니다. Claude Code를 설정하여 8시간마다 자동으로 토큰을 갱신함으로써, 수동 개입 없이 봇을 지속적으로 운영할 수 있습니다.