SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor

Claude Code invalid API key 오류 해결 방법

Claude Code에서 유효하지 않은 API 키 오류가 발생하는 원인을 분석합니다. 환경 변수 ANTHROPIC_API_KEY가 로그인 정보보다 우선순위가 높아 발생하는 문제이며, 이를 제거하여 구독 계정을 정상적으로 인식시키는 방법을 설명합니다.

Claude Code에서 잘못된 API key 오류가 표시되는 이유

Claude Code에서 Invalid API key 오류가 발생하는 이유는 2가지이며, 두 경우의 해결 방법은 서로 반대입니다. API key로 인증하려고 했지만 해당 key가 잘못되었거나, 취소되었거나, 다른 계정의 key일 수 있습니다. 또는 애초에 key를 사용할 의도가 없었지만, 서버 환경에 남아 있는 ANTHROPIC_API_KEY가 로그인한 subscription보다 우선 적용되고 있을 수 있습니다. 2026년 10월 기준 Anthropic 문서는 두 번째 경우를 명확히 설명합니다. 환경에 설정된 key 사용을 승인하면 로그인되어 있더라도 Claude Pro, Max, Team 또는 Enterprise subscription 대신 해당 key가 사용됩니다. 또한 claude -p에서는 key가 있으면 항상 해당 key가 사용됩니다.

무엇이든 변경하기 전에 어느 경우에 해당하는지 확인합니다. Claude Code를 시작하고 /status를 실행합니다. 문서에는 subscription 계정을 표시하는 Login method 행과 API key가 사용 중일 때 나타나는 API key 행이 설명되어 있습니다. /login만 실행한 적이 있는 서버에서 API key 행이 표시되면 환경, 설정 및 apiKeyHelper를 확인합니다. 다시 인증해도 해당 자격 증명은 제거되지 않습니다.

아래 내용은 모두 자신의 서버에서 실행하는 명령입니다. 출력 내용을 확인한 뒤 그 내용에 따라 조치합니다.

자격 증명 우선순위와 /login이 도움이 되지 않는 이유

여러 자격 증명이 있으면 Claude Code는 문서에 정의된 순서에 따라 하나를 선택합니다.

  • CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX 또는 CLAUDE_CODE_USE_FOUNDRY이 설정되어 있으면 cloud provider 자격 증명
  • ANTHROPIC_AUTH_TOKEN 변수. Authorization: Bearer 헤더로 전송됩니다.
  • ANTHROPIC_API_KEY 변수. X-Api-Key 헤더로 전송됩니다.
  • apiKeyHelper 스크립트의 출력
  • CLAUDE_CODE_OAUTH_TOKEN 변수. claude setup-token의 토큰을 저장합니다.
  • ANTHROPIC_PROFILE를 통해 명시적으로 선택한 Anthropic profile, 환경 변수로 선택한 federation 자격 증명, 그리고 oidc_federation 인증을 사용하는 활성 또는 기본 profile
  • /login이 기록하는 subscription OAuth 자격 증명
  • user_oauth 인증을 사용하는 활성 또는 기본 Anthropic profile. 단, ANTHROPIC_PROFILE으로 명시적으로 선택한 경우는 제외됩니다.

목록을 아래에서 위로 읽어 보십시오. /login은 subscription OAuth 자격 증명을 기록하며, Linux에서는 이 자격 증명이 파일 모드 0600으로 ~/.claude/.credentials.json에 저장됩니다. 이 자격 증명은 ANTHROPIC_PROFILE으로 명시적으로 선택하지 않은 한 활성 또는 기본 user_oauth profile보다 우선하지만, 환경 자격 증명과 apiKeyHelper보다는 낮습니다. 승인된 환경 API key는 subscription login보다 계속 우선합니다. 따라서 새로 login해도 세션이 실제로 사용하지 않는 자격 증명만 갱신됩니다. login 자체는 성공했지만 우선순위에서 밀린 것입니다. 명백해 보이는 해결 방법이 아무 효과가 없는 이유는 이것이 전부입니다. CLAUDE_CODE_OAUTH_TOKEN를 사용하면 /login이 현재 세션을 새 login으로 전환합니다. 그러나 이를 제거할 때까지 새 세션은 다시 변수를 읽습니다. Claude apps gateway에 로그인한 세션은 이 우선순위에 포함되지 않습니다. 이 세션은 cloud provider 변수가 설정되어 있어도 해당 자격 증명 대신 gateway token을 사용합니다.

대화형 세션에는 사용자를 혼란스럽게 하는 단계가 하나 더 있습니다. 문서에 따르면 환경에서 발견된 API key를 승인할지 거부할지 한 번 묻고, 선택한 결과를 기억합니다. 몇 달 전에 승인했다면 그 승인이 계속 적용되며 key는 login보다 계속 우선합니다. 거부했다면 다시 묻지 않고 key를 무시합니다. 이 경우에는 반대 상황이 발생합니다. 변수가 설정되어 있고 env에 표시되지만 세션은 이를 사용하지 않습니다. /config의 "Use custom API key" toggle로 선택을 변경할 수 있습니다. 이 toggle은 환경에 ANTHROPIC_API_KEY이 설정되어 있을 때만 표시됩니다. 비대화형 모드에서는 즉, script 또는 cron job 안에서 claude -p를 사용하는 경우에는 프롬프트가 전혀 표시되지 않습니다. key가 있으면 항상 사용됩니다.

VPS에서 남아 있는 ANTHROPIC_API_KEY를 어떻게 찾습니까?

먼저 Claude Code를 시작하는 셸에 해당 변수가 존재하는지 확인합니다.

env | grep -i anthropic

그런 다음 Anthropic의 문제 해결 페이지에서 안내하는 수정 명령을 실행합니다. 이 명령은 동시에 테스트 역할도 합니다.

unset ANTHROPIC_API_KEY
claude

Claude Code가 시작되고 /status에 구독 정보가 표시되면 원인을 확인한 것입니다. 시작 파일이 계속 해당 변수를 설정하면 다음 셸에서 변수가 다시 나타납니다. unset은 명령을 입력한 셸만 변경하기 때문입니다. 이 절의 나머지 내용에서는 해당 변수를 설정하는 위치를 찾습니다.

셸 프로필 및 시스템 전역 환경 파일

grep -rn ANTHROPIC ~/.bashrc ~/.bash_profile ~/.profile ~/.zshrc \
  ~/.config/fish/config.fish /etc/environment /etc/profile /etc/profile.d/ 2>/dev/null

Anthropic 문서에는 ~/.zshrc, ~/.bashrc, ~/.profile가 나옵니다. 서버에서는 검색 범위를 넓혀야 합니다. 로그인 PAM(플러그형 인증 모듈) 설정에서 활성화된 경우 pam_env 모듈이 /etc/environment을 읽습니다. 이 방식으로 시스템 전역 키가 세션에 들어올 수 있습니다. /etc/profile.d/의 파일은 로그인 셸의 프로필이 해당 파일을 source할 때 실행됩니다. systemd 서비스는 .bashrc을 자동으로 읽지 않습니다. 서비스 명령이 명시적으로 셸을 시작하거나 프로필을 source하는지 확인합니다. 확인해야 할 파일은 Claude Code를 시작한 방식에 따라 달라집니다.

systemd 유닛

유닛은 셸 프로필을 읽지 않습니다. 유닛과 모든 drop-in에 있는 Environment= 및 EnvironmentFile= 줄과 서비스 관리자가 제공하는 변수가 해당 유닛의 환경에 포함됩니다.

systemctl cat claude-agent.service
systemctl show -p Environment claude-agent.service

systemctl cat은 drop-in과 /etc/systemd/system/claude-agent.service.d/ 아래의 override를 포함하여 유닛 파일과 모든 drop-in을 출력합니다. systemctl show -p Environment은 유닛의 Environment= 할당을 표시합니다. EnvironmentFile= 파일도 확인해야 합니다. 프로세스가 시작될 때 해당 파일의 내용을 별도로 읽기 때문입니다. 자신의 사용자로 실행되는 서비스라면 두 명령에 모두 --user을 추가합니다. 유닛을 수정한 뒤에는 sudo systemctl daemon-reload를 실행하고 서비스를 재시작합니다. 프로세스가 시작될 때 환경이 구성되며, 실행 중인 프로세스는 전달받은 환경을 계속 유지하기 때문입니다.

수정 사항보다 오래 실행된 tmux 및 screen 세션

이 문제로 몇 시간씩 소요될 수 있습니다. tmux 서버는 시작할 때의 환경을 유지하며, 새 pane은 전역 환경과 세션 환경을 병합한 값을 상속합니다. .bashrc에서 export를 제거하고 새 pane을 열어도 이전 키가 계속 남아 있을 수 있습니다.

tmux show-environment | grep -i ANTHROPIC
tmux set-environment -r ANTHROPIC_API_KEY

set-environment -r는 tmux가 새 프로세스에 전달하는 환경에서 제거할 이름을 지정합니다. -g를 추가하면 서버의 전역 환경에서도 같은 작업을 수행합니다. 이미 열린 pane은 자체 복사본을 계속 유지합니다. 프로세스 환경은 해당 프로세스 내부에서만 변경할 수 있기 때문입니다. export를 제거한 뒤에는 세션에서 detach하고 tmux kill-server를 실행한 다음 새 세션을 시작하는 것이 확실합니다. VPS에서 장시간 실행되는 Claude Code 세션을 tmux로 설정하기 전에 이 점을 알아두는 것이 좋습니다. 해당 세션은 설정을 3번 수정하는 동안에도 계속 실행될 수 있는 프로세스이기 때문입니다.

이미 실행 중인 프로세스의 환경을 읽으려면 커널에 요청합니다.

tr '\0' '\n' < /proc/$(pgrep -n claude)/environ | grep -i anthropic

이 명령은 exec 시점에 프로세스에 전달된 값을 출력합니다. Claude Code가 설정에서 나중에 불러온 값처럼 이후에 변경된 내용은 반영하지 않습니다. 해당 파일을 읽으려면 프로세스 소유자 또는 root여야 합니다. 여러 프로세스가 실행 중이면 pgrep -n claude은 가장 최근 일치 항목을 선택하므로 PID를 확인합니다.

Docker 및 Compose

docker exec claude-agent env | grep -i anthropic
docker compose config

첫 번째 명령은 실행 중인 컨테이너 내부의 환경을 표시합니다. 여기에는 --env-file, environment: 블록 또는 이미지에 포함된 ENV 줄에서 전달된 값이 포함됩니다. docker compose config은 변수를 해석한 compose 파일을 출력합니다. 따라서 작성한 ${ANTHROPIC_API_KEY} 자리 표시자가 아니라 실제로 전달될 값을 확인할 수 있습니다. 두 명령 모두 비밀 값을 터미널에 출력하므로, 출력 내용을 지울 수 있는 세션에서 실행합니다. Compose는 기본적으로 프로젝트 디렉터리의 .env 파일도 보간에 사용합니다. Compose 설정이 해당 값을 전달하면 그 값이 컨테이너에 들어갑니다.

모든 셸 수정 후에도 남아 있는 설정 파일

Claude Code 설정 파일에는 env 블록이 포함됩니다. 문서에는 충돌 규칙도 명확히 설명되어 있습니다. 같은 변수가 셸과 설정 파일의 env 블록 양쪽에 설정된 경우 대부분의 세션에서는 설정 파일의 값이 적용됩니다. 예외는 Claude Desktop 앱 또는 self-hosted 환경 runner에서 시작한 세션입니다. 이 경우에는 시작 환경이 우선합니다. 서버의 터미널에서 시작한 claude에서는 설정 파일에 기록된 키가 입력한 모든 unset보다 우선합니다.

grep -rn ANTHROPIC ~/.claude/settings.json .claude/settings.json .claude/settings.local.json 2>/dev/null

사용자 파일뿐 아니라 프로젝트 파일도 확인합니다. .claude/settings.json은 일반적으로 커밋되므로 저장소를 clone하는 모든 사용자와 공유됩니다. 조직에서 관리형 설정을 배포할 수도 있으며, 이 설정은 사용자의 자체 파일보다 우선합니다. 제거할 수 없는 키를 찾았다면 해당 조직의 관리자에게 문의합니다.

다른 경우: 키 자체가 잘못된 경우

/status에 API key가 표시되고 그것이 의도한 결과라면, 오류를 표시된 그대로 받아들여야 합니다. Anthropic의 오류 참조에 따르면 Invalid API key · Fix external API key은 API가 ANTHROPIC_API_KEY 또는 apiKeyHelper 스크립트에서 전달된 키를 거부했거나, Claude Code가 전송 전에 키를 차단했다는 의미입니다. 이 오류에서는 다음을 확인합니다.

  • 키에 오타가 있는지 확인합니다.
  • Console에서 키가 폐기되지 않았는지 확인합니다.
  • direnv, dotenv 셸 플러그인 또는 IDE 터미널 같은 도구가 프로젝트의 .env 파일에서 오래된 키를 불러오지 않았는지 확인합니다.

스크롤백에 값을 출력하지 않고 값을 확인합니다.

echo "len=${#ANTHROPIC_API_KEY} tail=${ANTHROPIC_API_KEY: -6}"

예상한 값보다 길이가 1~2자 더 길다면, 대개 복사하여 붙여 넣는 과정에서 줄 바꿈이나 따옴표가 함께 들어갔거나, 키 파일이 Windows 줄 끝 형식으로 저장되어 carriage return이 남은 경우입니다. $(cat keyfile)로 파일을 읽어도 일반적인 후행 newline은 유지되지 않습니다. Bash가 명령 치환 출력에서 후행 newline을 삭제하기 때문입니다. 그러나 해당 newline 앞의 carriage return은 삭제하지 않습니다. 따라서 Windows 줄 끝 형식의 파일은 변수에 문자 1개를 추가로 남깁니다. 최신 버전은 전송 전에 헤더에 포함할 수 없는 문자를 감지합니다. 메시지가 Fix external API key 뒤에 Invalid X-Api-Key header value from ANTHROPIC_API_KEY: it contains a line break 같은 설명과 함께 계속되면 Claude Code가 요청을 중지하므로 API에는 키가 전달되지 않습니다. 둥근 따옴표도 같은 검사에서 감지됩니다. 그러나 곧은 따옴표는 유효한 헤더 문자이므로 X-Api-Key 헤더의 일부로 전송되고, 전송되는 자격 증명은 생성한 키가 아닙니다.

같은 출력에서 ANTHROPIC_AUTH_TOKEN도 확인해야 합니다. 자격 증명 우선순위에서 API key보다 앞에 있기 때문입니다. 프록시를 시험하면서 남은 bearer token이 있다면, 지금 수정 중인 키는 실제로 전송되는 자격 증명이 아닙니다. 해당 출력에서는 ANTHROPIC_BASE_URL도 확인할 가치가 있습니다. 오래된 값이 더 이상 존재하지 않을 수 있는 gateway를 클라이언트가 가리키게 할 수 있기 때문입니다. 헤더 수준의 동작은 Anthropic API key 인증 방식에서 각각의 값이 전달하는 내용을 설명합니다. 이 시스템에 어떤 자격 증명을 보관할지 결정하기 전에 subscription login과 API key의 차이를 참고할 수 있습니다.

이 오류는 용량 문제를 의미하지 않습니다. 요청이 529 Overloaded으로 실패한다면 과부하된 모델 오류를 확인해야 합니다. 이 경우 자격 증명을 변경할 필요가 없습니다.

apiKeyHelper 스크립트가 실패하는 이유는 무엇입니까?

apiKeyHelper는 Claude Code가 자격 증명을 가져오기 위해 실행하는 스크립트의 이름을 지정하는 설정 키입니다. vault에서 가져오는 키처럼 교체되거나 수명이 짧은 토큰에 사용합니다. 필요한 동작은 간단합니다. 현재 키를 표준 출력으로 출력하고 성공적으로 종료해야 합니다. 문서에 따르면 오류와 함께 종료되거나, 시간 초과가 발생하거나, 아무것도 출력하지 않는 스크립트를 사용하면 3회 이내에 Your apiKeyHelper script is failing와 함께 요청이 실패합니다.

직접 실행하여 이 두 가지 조건을 모두 확인합니다.

out=$(/usr/local/bin/anthropic-key.sh)
echo "exit=$? len=${#out} tail=${out: -6}"

키를 올바르게 출력했더라도 0이 아닌 종료 코드는 실패입니다. 키를 출력하기 전에 표준 출력으로 Fetching credential...를 출력하는 helper도 실패입니다. v2.1.227부터 Claude Code는 키 이외의 내용이 포함된 출력을 거부하고 helper가 returned output that cannot be used as an API key라고 보고합니다. 이전 버전에서는 해당 줄을 자격 증명의 일부로 함께 전달했습니다. 진행 메시지는 표준 오류로 보내야 합니다. 세션 내에서 /status를 실행하면 마지막 종료 코드와 오류 출력을 포함한 Failing 내용을 표시하는 apiKeyHelper 행이 나타납니다.

그런 다음 서비스가 실행하는 방식으로 테스트합니다.

env -i HOME="$HOME" PATH=/usr/bin:/bin /usr/local/bin/anthropic-key.sh
echo "exit=$?"

env -i는 거의 비어 있는 환경에서 스크립트를 시작합니다. helper가 .bashrc가 PATH에 추가하는 디렉터리에서 aws, vault 또는 gcloud를 호출하면 직접 테스트할 때는 동작하지만, 실행 환경에 해당 디렉터리가 없는 서비스에서는 실패합니다. 스크립트가 실행 가능한지 확인하고, 스크립트가 호출하는 모든 항목에 절대 경로를 사용해야 합니다. 또는 스크립트 내부에서 PATH를 설정합니다.

서버에서는 문서에 명시된 동작 2가지도 중요합니다. Claude Code는 기본적으로 5분 후 helper를 다시 실행합니다. CLAUDE_CODE_API_KEY_HELPER_TTL_MS로 다른 간격을 설정할 수 있습니다. 따라서 시작 시에는 동작하지만 1시간 후에 실패하는 설정은 시작 시점이 아니라 갱신 시점에 실패하는 것입니다. helper가 키를 반환하는 데 10초 넘게 걸리면 Claude Code는 경과 시간과 함께 프롬프트 바에 경고 알림을 표시합니다. 이 알림은 호출이 느리다는 뜻이지 호출이 실패했다는 뜻은 아닙니다. 시간 초과로 오류가 발생하기 전에 문제를 알려 주는 초기 경고입니다.

이 서버에 API 키가 정말로 필요한가?

해결책이 항상 삭제인 것은 아닙니다. 다음과 같은 경우에는 키를 유지해야 합니다:

  • Console에 청구되는 VPS의 무인 에이전트는 개인 구독 한도를 소모하지 않습니다.
  • claude -p이 승인을 위한 터미널을 갖지 못하고 키가 존재할 때 항상 사용되는 비대화형 실행 환경인 경우.
  • 구독이 연결되지 않은 머신.
  • 개인 구독 로그인 정보를 저장해서는 안 되는 공유 머신이나 클라이언트 머신.

비용이 보통 이 결정을 좌우하며, API 및 구독 요금 비교에서 이를 계산할 수 있습니다.

본인 소유의 머신이고 이미 구독료를 지불하고 있다면 키를 삭제하십시오. 그 후 삭제 상태를 유지하십시오. 모든 대화형 셸이 상속받는 ~/.bashrc에 키를 export하는 대신, 키가 필요한 서비스에만 제공하십시오:

[Service]
EnvironmentFile=/etc/claude-agent.env

이 파일의 권한은 600으로 설정하고, 서비스를 실행하는 사용자가 소유하도록 하십시오. 대화형 세션은 이 파일을 보지 않으므로, 본인의 claude는 계속 구독 정보를 사용하고 서비스는 키를 사용하게 됩니다. 브라우저가 없는 환경에서 구독 자격 증명이 필요하다면, claude setup-token을 실행하여 CLAUDE_CODE_OAUTH_TOKEN에 붙여넣을 OAuth 토큰을 출력하십시오. 이 토큰을 사용하기 전에 문서화된 제한 사항을 알아두는 것이 좋습니다. 이 토큰은 모델 요청만 수행할 수 있으므로, Remote Control 세션이나 claude.ai 커넥터는 사용할 수 없습니다. 머신당 한 번 이 결정을 내리고 unit 파일에 기록하는 것이 이 페이지에서 다루는 오류를 방지하는 방법입니다. 아무도 설정한 기억이 없는 키로 인해 문제가 시작되기 때문입니다. 자격 증명을 배치한 후 접근 범위를 제한하는 것은 별도의 작업이며, VPS에서 안전하게 Claude Code 실행하기에서 다룹니다.

강력한 조치를 취하기 전 주의 사항이 하나 있습니다. /logout은 저장된 자격 증명을 삭제합니다. 문서에 따르면 이 명령은 저장된 MCP(Model Context Protocol) 서버 로그인 정보와 플러그인 비밀 정보도 함께 삭제하므로, 이후 다시 인증해야 할 수 있음을 유의하십시오.

FAQ

Claude Code에서 구독 중인데도 invalid API key라고 표시되는 이유는 무엇입니까?

승인된 ANTHROPIC_API_KEY이 환경 변수에 있으면 구독 로그인보다 우선하기 때문입니다. Anthropic의 문서에 따르면 환경 변수에 설정된 승인된 key는 로그인된 상태에서도 Pro, Max, Team 또는 Enterprise 구독 대신 사용됩니다. 또한 비대화형 모드에서 -p가 있으면 해당 key가 항상 사용됩니다. Claude Code 안에서 /status을 실행하면 세션이 선택한 자격 증명을 확인할 수 있습니다. API key 행이 표시되는데 의도적으로 설정한 적이 없다면 unset ANTHROPIC_API_KEY를 실행한 다음 claude을 다시 시작해 원인을 확인합니다.

/login을 실행하면 invalid API key 오류가 해결됩니까?

승인된 환경 API key가 계속 사용되는 동안에는 해결되지 않습니다. /login은 구독 OAuth 자격 증명을 환경 자격 증명과 apiKeyHelper보다 낮은 우선순위로 기록하지만, ANTHROPIC_PROFILE이 명시적으로 선택하지 않은 경우에는 활성 또는 기본 user_oauth 프로필보다 높은 우선순위로 기록합니다. 로그인은 성공하지만 이후 우선순위에서 밀려 사용되지 않으므로, 로그인을 반복해도 아무런 변화가 없습니다. 변수가 설정된 위치에서 해당 변수를 제거하거나 /config에서 "Use custom API key" 토글을 끕니다. 문서에 따르면 이 토글은 ANTHROPIC_API_KEY가 환경에 설정된 경우에만 표시됩니다.

Claude Code가 사용하는 인증 방식을 확인하려면 어떻게 해야 합니까?

세션에서 /status을 실행합니다. 문서에서는 구독 계정을 나타내는 Login method 행과 API key가 사용 중일 때 표시되는 API key 행을 설명합니다. 이를 Claude Code를 시작한 동일한 셸의 env | grep -i anthropic과 비교합니다. 서비스나 컨테이너에서 Claude Code를 실행한다면 tr '\0' '\n' < /proc/<pid>/environ로 실행 환경을 확인합니다. 해당 파일에는 exec 시점에 전달된 값이 표시되므로, Claude Code가 이후에 읽는 설정 파일의 값도 확인합니다.

apiKeyHelper 스크립트를 직접 실행하면 정상적으로 동작합니다. 그런데 Claude Code가 계속 실패하는 이유는 무엇입니까?

대개 환경이나 종료 상태가 원인입니다. Claude Code는 자체 프로세스 환경에서 helper를 실행합니다. 따라서 터미널에는 있지만 서비스에는 PATH 항목이 없으면, 터미널에서 테스트할 때는 동작하는 명령을 찾지 못합니다. env -i HOME="$HOME" PATH=/usr/bin:/bin /path/to/helper로 테스트하고 이후 echo $?을 확인합니다. 문서에서 정의한 실패에는 스크립트가 오류와 함께 종료하거나, 시간 초과가 발생하거나, 아무것도 출력하지 않거나, key 이외의 내용을 출력하는 경우가 포함되며, Your apiKeyHelper script is failing로 표시됩니다. v2.1.227부터는 표준 출력에 배너나 로그 행이 있으면 helper가 즉시 실패하므로, 진행 메시지는 표준 오류로 보내야 합니다.

이 글이 도움이 되었나요?