거절 응답이 이제 HTTP OK를 반환합니다 — try-except로는 잡히지 않습니다

v0.108–v0.109는 HTTP 200 거절 응답 추가, 새로운 stop_reason 리터럴 도입, 타입 열거형에서 은퇴 모델 문자열 제거를 포함합니다.

거절 응답이 이제 HTTP OK를 반환합니다 — try-except로는 잡히지 않습니다
Share

Anthropic의 공식 Python SDK가 일주일 사이에 네 차례 릴리스됐습니다 — 그중 세 개는 6월 9일 하루 여덟 시간 안에 쏟아졌고 — 그 어느 것도 공식 "breaking" 딱지를 달지 않았습니다. 라이브러리가 pre-1.0이기 때문에 그 딱지가 없는 것이지, 여러분 코드가 안전해서가 아닙니다.

v0.109.2, 도입해도 될까? 주석 달린 변경 이력

대체로 괜찮습니다 — 단, 버전을 올리기 전에 diff를 먼저 읽어보세요. anthropic Python SDK는 0.x 트랙을 따르므로, 모든 항목은 "Breaking" 대신 Features, Bug Fixes, Chores로 분류됩니다 . 그럼에도 6월 9일~15일 사이에는 프로덕션 응답을 조용히 잘못 처리하게 만드는 세 가지 경로가 새로 생겼습니다. 업그레이드 전에 각각을 테스트해보세요. 태그가 없다는 건 버저닝 관례의 산물이지, 호환성 보장이 아닙니다.

한줄 요약: v0.109.2는 현재 PyPI 최신 릴리스로 도입 가능하지만, 타입 열거형에서 은퇴한 모델 식별자를 제거하기 때문에 — 더 이상 지원되지 않는 모델 문자열을 참조하는 코드베이스는 mypy 오류나 런타임 오류를 맞닥뜨릴 수 있습니다. 6월 9일에 나온 세 릴리스(v0.108.0~v0.109.1)는 명시적으로 처리해야 하는 거부(refusal) 및 폴백 동작을 추가합니다.

아래는 GitHub Releases와 PyPI 양쪽에서 모두 확인된 주석 달린 릴리스 순서입니다 :

버전릴리스 일시 (UTC)유형변경 내용
v0.108.06월 9일 16:37Featuresclaude-fable-5claude-mythos-5 추가, 서버 측 거부 폴백 경로, 클라이언트 측 재시도 래퍼 추가
v0.109.06월 9일 20:04FeaturesManaged Agents 수명주기 인터페이스; 구성된 엔드포인트 106 → 116으로 증가; beta.deploymentsbeta.deployment_runs 추가
v0.109.16월 9일 23:55Bug FixesRefusalStopDetails.category Literal 유니온에 frontier_llm 추가
v0.109.26월 15일Chores타입 열거형 및 목록에서 은퇴한 모델 식별자 제거

핵심은 v0.108.0(커밋 6b76649)입니다. 이 버전은 BetaFallbackState, BetaRefusalFallbackMiddleware, RetryableError, OverloadedError, RequestTooLargeError를 내보내고, 거부 시 서버 측 및 클라이언트 측 폴백을 모두 다루는 examples/fallbacks.py를 함께 제공합니다 . 중요한 건 새 타입 자체가 아니라 — 그 타입들이 묘사하는 새로운 모델 동작입니다.

업그레이드 후 조용히 깨질 수 있는 세 가지 지점:

  • HTTP-200 거부 응답: Fable 5의 거부 응답은 오류가 아닌 stop_reason: refusal이 담긴 200으로 반환되므로, try/except로는 잡히지 않습니다 .
  • 네 번째 거부 카테고리 추가: v0.109.1이 카테고리 유니온에 frontier_llm을 추가해 — v0.108.0 기준으로 작성된 완전 매처(exhaustive matcher)에서 타입 오류가 발생합니다 .
  • 모델 문자열 제거: v0.109.2가 은퇴한 식별자를 삭제해 — 즉각적인 mypy 오류나 런타임 오류로 이어질 가능성이 가장 높은 항목입니다 .

이어지는 섹션에서는 위 각 항목을 한 줄씩 주석과 함께 설명합니다 — diff가 무엇을 말하는지, 그리고 이미 배포된 코드에 어떤 영향을 미치는지 .

HTTP 성공 응답에 거부 카테고리가 담길 때

Refusals now return HTTP OK — and your try-except misses them

Fable 5의 거부는 예외가 아닙니다 — 성공 응답입니다. API는 HTTP 200과 함께 stop_reason: "refusal"을 반환하고, stop_details.category 필드에 거부한 분류기 이름을 담아 돌려줍니다 — 전송 계층에서 잡을 수 있는 에러를 발생시키는 대신 . 네 가지 카테고리가 정의되어 있습니다: cyber, bio, frontier_llm, reasoning_extraction .

이것이 마이그레이션의 위험입니다. APIStatusError만 감지하고 모든 200 응답이 end_turn 또는 max_tokens로 끝난다고 가정하는 경로는 거부를 그대로 정상 성공 분기로 흘려보냅니다 — 빈 출력이나 잘린 출력이 나올 뿐, 아무 신호도 발생하지 않습니다. 호출을 감싼 try/except는 절대 실행되지 않습니다 — 아무것도 throw되지 않으니까요 .

"Claude Fable 5의 거부는 HTTP 200과 함께 stop_reason: refusal을 반환합니다. 응답에는 어떤 분류기가 요청을 거부했는지 명시됩니다." — Anthropic API 문서 (source: commit 6b76649)

과금 모델은 이를 잘못 처리했을 때의 비용을 완화해 줍니다. 거부된 호출은 출력이 생성되기 전에는 과금되지 않으며, Claude Opus 4.8로 자동 재시도가 발생할 때 서버 측 폴백 크레딧 덕분에 프롬프트 캐시 비용을 두 번 내지 않아도 됩니다 . Anthropic에 따르면 이 폴백은 출시 당시 평균 세션의 5% 미만에서 발생합니다 — 테스트되지 않은 거부 처리 코드를 배포해도 오랫동안 정상처럼 보일 만큼 드문 일입니다 .

새 모델에는 두 가지 인터페이스 제약이 함께 제공되며, 구버전 Claude에 대한 가정을 그대로 갖고 있는 클라이언트라면 에러로 나타납니다:

  • 적응형 사고는 항상 켜져 있습니다. thinking.type: "disabled"를 전송하면 유효성 검사 오류가 발생합니다 — Fable 5나 Mythos 5에는 사고를 끄는 경로가 없습니다 .
  • 원시 사고 연쇄(chain-of-thought)는 절대 반환되지 않습니다. thinking.display로 제한된 요약 블록만 반환됩니다. 원시 추론 텍스트를 파싱하던 코드는 아무것도 읽지 못합니다 .

특정 사용자는 아예 배제됩니다. Fable 5와 Mythos 5는 30일 데이터 보존이 적용되는 Covered Model로, 제로 데이터 보존 조건에서는 제공되지 않습니다. 따라서 ZDR 제약이 있는 호출자는 거부 처리 코드와 무관하게 이 모델들을 도입할 수 없습니다 . 그 외의 모든 사용자에게 실질적인 수정은 작지만 필수적입니다. 200 응답을 완료된 턴으로 처리하기 전에 stop_reason을 분기하고, refusal을 일급 결과로 처리하세요.

v0.109.1의 네 번째 거부 카테고리 — 엄격한 타입 유니온에 미치는 영향

2026년 6월 9일 출시된 v0.109.1은 한 줄의 타입 변경이지만 파급 범위가 넓습니다. RefusalStopDetails.categoryBetaRefusalStopDetails.category 양쪽에서 거부 카테고리 유니온을 Literal['cyber', 'bio', 'reasoning_extraction']에서 Literal['cyber', 'bio', 'frontier_llm', 'reasoning_extraction']으로 확장합니다 . 새로운 frontier_llm 값은 프론티어 모델 분류기에 의해 요청이 거부되었음을 알려줍니다 — 일부 세션을 Opus 4.8로 라우팅하는 바로 그 안전장치입니다. 이 릴리스 이전에 작성된 거부 핸들러라면 해당 값의 존재를 알지 못합니다.

이 간극은 코드의 엄격성에 따라 다르게 나타납니다:

  • 세 값 유니온에 대해 작성된 완전 열거형 match 구문은 default 분기로 빠져나갑니다 — Python은 런타임에서 완전성을 강제하지 않으므로 조용히 누락됩니다.
  • 구 카테고리를 열거하는 TypeGuard 분기frontier_llm에 대해 False를 반환하며, 실제 거부를 알 수 없는 응답으로 잘못 라우팅합니다.
  • v0.108 스키마로 생성된 Pydantic 판별 유니온은 해당 값을 즉시 ValidationError로 거부합니다 — 파싱 시점에서 하드 실패가 발생합니다.

같은 실패, 다른 증상이라는 분열이 함정입니다. 느슨하게 타입된 코드는 케이스를 조용히 넘어가고, 엄격하게 타입된 코드는 예외를 발생시킵니다. 어느 쪽도 거부를 인식하는 경로에서 원하는 동작이 아닙니다.

더 미묘한 위험: 환경에 오래된 스키마 객체가 캐시되어 있으면 mypy가 불일치를 알려주지 않습니다. v0.108 스키마로 생성된 Pydantic 모델은 버전 업 후 반드시 재생성해야 합니다 — 정적 분석은 SDK에 포함된 유니온이 아니라 로컬 아티팩트가 여전히 인코딩하고 있는 유니온을 봅니다 . 재생성 없이 패키지만 업그레이드하면 잘못된 계약을 대상으로 타입 검사를 하게 됩니다.

Simon Willison이 LLM 툴링에 대해 말했듯, "문서가 곧 소스 코드"입니다 — 그리고 여기서 실제 계약은 패치 레벨 버전 문자열이 아니라 커밋 히스토리에 담겨 있습니다. 버그 수정으로 태그된 변경 사항도 stop-details 파싱에 내재된 모든 가정을 무효화할 수 있습니다.

수정 방법은 기계적이지만, 거부를 분기하는 핸들러를 배포하기 전에 반드시 적용해야 합니다:

  • anthropic을 ≥v0.109.1로 고정하세요 .
  • 모든 완전 열거형 match 분기와 TypeGuard 분기에 frontier_llm을 추가하세요.
  • category Literal에 네 가지 값이 모두 포함되도록 Pydantic 모델을 재생성하세요.

v0.109.2가 타입 열거형에서 지원 종료 식별자를 제거하는 방식

Refusals now return HTTP OK — and your try-except misses them

2026년 6월 15일에 출시된 v0.109.2 는 SDK의 타입화된 Literal 열거형에서 퇴역 모델 식별자 문자열을 제거합니다 . 이로 인한 오류는 이론적인 얘기가 아닙니다. 제거된 이름을 아직도 전달하는 호출자는 두 가지 방식 중 하나로 실패합니다. 해당 문자열이 타입이 지정된 매개변수를 통해 흐를 경우 mypy 또는 pyright가 좁혀진 유니언에 대해 타입 오류를 발생시킵니다. 동적으로 해석되는 경우에는 식별자가 더 이상 존재하지 않아 런타임 조회 오류가 발생합니다. 6월 9~15일 릴리스 묶음 중 실제 동작하는 코드를 깰 가능성이 가장 높은 변경 사항입니다.

이 지원 종료는 예고 없이 이루어진 것이 아닙니다. Claude Opus 4.1은 이미 v0.106.0 시점에 deprecated로 표시되었고, v0.109.2에서 제거가 완료됩니다 . 이전 지원 종료 공지를 읽고 마이그레이션을 완료한 팀은 버전 업에서 아무런 손실이 없습니다. 무시한 팀은 이제 오류 상태에 놓입니다 — "deprecated"와 "removed" 사이의 유예 기간이 닫혔습니다.

릴리스날짜퇴역 모델 ID 상태
v0.106.0이전Claude Opus 4.1 deprecated 표시 (아직 사용 가능)
v0.109.22026-06-15퇴역 식별자가 타입 열거형에서 제거됨

한 가지 현실적인 한계가 있습니다. 릴리스 노트에는 제거된 식별자가 모두 열거되어 있지 않습니다 . 영향 범위를 파악하려면, 코드베이스 전체에서 model= 문자열 리터럴을 grep하고 업그레이드가 조용히 통과된다고 믿기보다는 v0.109.2 CHANGELOG diff와 각 항목을 대조 확인해야 합니다.

배포 시 예상치 못한 문제를 피하려면 아래 순서로 마이그레이션하세요:

  • 먼저 감사. 환경 변수와 기능 플래그에서 로드되는 값을 포함해 모든 model= 리터럴과 설정 기반 모델 문자열을 grep하세요.
  • 버전 올리기 전에 교체. 현재 고정된 버전을 유지한 채로 각 deprecated 식별자를 현재 동등한 값으로 교체해 동작이 변경되지 않도록 하세요.
  • 버전 올린 후 검증. v0.109.2로 업그레이드한 다음 mypy를 strict 모드로 실행해 배포 전에 남은 위반 사항을 찾아내세요.
  • 동적 경로를 주시하세요. strict 타이핑은 런타임에 조합되는 모델 이름을 잡아내지 못합니다 — 앱이 참조하는 모델마다 실제 요청을 한 번씩 보내는 스모크 테스트를 추가하세요.

이번 릴리스 윈도우 전반에 걸쳐 나타나는 패턴이 여기서도 유효합니다. 낮은 패치 번호가 낮은 영향 범위를 의미하지 않습니다. v0.109.2를 사소한 업데이트가 아닌 제거(removal)로 취급하세요.

v0.109.0, 라이프사이클 제어 인터페이스 추가

Refusals now return HTTP OK — and your try-except misses them

2026년 6월 9일 20:04 UTC에 출시된 v0.109.0 은 이 윈도우에서 일반적인 Messages 호출자에게 영향 범위가 전혀 없는 유일한 릴리스입니다. Managed Agents 배포 지원과 환경 변수 자격증명을 추가합니다 . messages.create만 호출한다면 이 변경 사항은 관계없습니다. Anthropic의 베타 배포 API에서 에이전트를 실행한다면, 직접 작성한 HTTP 코드를 타입화된 Python으로 대체합니다.

이 커밋은 configured_endpoints를 106개에서 116개로 — 10개의 새로운 라이프사이클 동사를 추가하고, beta.deploymentsbeta.deployment_runs 리소스를 도입합니다 . 이 분류는 라이프사이클 제어와 깔끔하게 대응됩니다:

  • beta.deployments — create, retrieve, update, list, archive, pause, run, unpause.
  • beta.deployment_runs — retrieve, list.

배포 객체에 8개의 동사, 실행 객체에 2개입니다. 이번 릴리스에는 지원 타입 표면도 포함됩니다. schedule, resource, vault, networking, 환경 변수 자격증명 타입이 함께 Managed Agents 설정 계약 전체를 기술합니다 . SDK를 벗어나지 않고도 에이전트 배포를 프로비저닝하고, 스케줄링하고, 해제할 수 있습니다.

이 계약은 안정된 상태가 아니라 변화 중인 것으로 취급해야 합니다. 3일 앞선 6월 6일에 출시된 v0.107.0은 이미 changelog에서 다음과 같이 기술한 내용을 포함하고 있었습니다:

"small updates to Managed Agents types" — anthropic-sdk-python CHANGELOG (source: CHANGELOG.md)

즉, v0.107에서 v0.109에 이르는 구간에서 Managed Agents 형태가 연속적인 마이너 버전에 걸쳐 변경되고 있음을 알 수 있습니다 . 이 타입들이 안정적으로 유지되어야 하는 도구를 사용한다면, 0.x 라인의 최신을 추적하기보다 특정 마이너 버전에 고정하세요. 릴리스 노트는 타입 정의 이상의 생성자 옵션이나 재시도 동작을 문서화하지 않으므로, 정확한 형태가 필요할 때는 커밋 47633bf를 직접 확인하세요 .

정부 명령으로 중단된 v0.108.0 신기능

v0.108.0의 폴백 메커니즘은 이제 호출할 수 없는 모델을 대상으로 제공됩니다. 2026년 6월 12일 오후 5시 21분(ET 기준), 미국 정부의 수출통제 지침에 따라 외국인 — Anthropic 소속 외국인 직원 포함 — 을 대상으로 Claude Fable 5 및 Mythos 5 접근이 중단되었습니다 . Anthropic은 사용자별 선택적 차단 대신 모든 고객을 대상으로 두 모델을 일괄 비활성화했으며, 나머지 모델은 영향을 받지 않았습니다 .

새 폴백 경로를 위해 업그레이드한 사용자에게는 실질적인 타격입니다. SDK 코드 — BetaFallbackState, BetaRefusalFallbackMiddleware, examples/fallbacks.py — 는 설치된 라이브러리에 포함되어 있지만, API는 해당 모델 ID 호출을 거부합니다 . 미들웨어를 임포트하고 인스턴스화할 수는 있지만, 실제로 연결할 라이브 대상이 없습니다.

Anthropic은 이를 동의로 표현하지 않았습니다. 런치 기사는 6월 12일 중단 사실을 반영해 업데이트되었으며 , Anthropic은 공개적으로 해당 지침에 구체적인 세부 내용이 없었으며, 이 우려 사항이 특정하고 보편적이지 않은 탈옥에 해당한다고 이해하며, 리콜이 정당하다는 데 동의하지 않는다고 밝혔습니다.

"리콜이 정당하다는 데 동의하지 않으며, 해당 우려 사항은 특정하고 보편적이지 않은 탈옥에 해당한다고 이해합니다." — Anthropic, 중단 성명 (source: commit d3a806b).

정부의 근거 자료는 검토된 출처에서 공개되어 있지 않습니다 . 재개 일정에 관계없이 두 가지 제약이 유지됩니다:

  • Mythos 5는 일반 공개에 도달한 적이 없습니다. 출시 시 Project Glasswing으로만 한정되었기 때문에 대부분의 팀은 처음부터 잃을 프로덕션 접근 권한 자체가 없었습니다 .
  • ZDR 제외 조건은 유지됩니다. 두 모델 모두 30일 보존 기간이 적용되는 Covered Model이며, 제로 데이터 보존(ZDR)으로는 제공되지 않습니다 .

2026년 6월 19일 기준 실질적인 결론: v0.108.0의 거부 폴백 기능은 도입은 가능하지만 아직 실행할 수 없는 코드로 취급하세요. HTTP-200 거부 처리와 frontier_llm 카테고리는 지금 연결해두면 접근이 재개될 때 바로 준비된 상태가 됩니다 — 단, Anthropic이 중단 해제를 공식 확인할 때까지 프로덕션 경로를 claude-fable-5에 고정하지 마세요 .

자주 묻는 질문

기존 try-except 블록으로 Fable 5 거부 응답을 잡을 수 있나요?

아니요. Claude Fable 5의 거부 응답은 예외가 아닌 일반 Message 응답 안에 stop_reason: "refusal"과 함께 HTTP 200으로 반환됩니다 . 따라서 APIStatusError 및 유사한 핸들러는 작동하지 않습니다. 모든 호출 후 message.stop_reason을 확인하고, message.stop_details.category를 읽어 어떤 분류기가 거부했는지 파악하세요.

v0.109.2에서 제거된 모델 문자열과 코드베이스에서 찾는 방법은?

v0.109.2(2026년 6월 15일)는 API 및 SDK에서 은퇴 모델을 제거했습니다 . 릴리스 노트에 제거된 모든 이름이 나열되어 있지는 않지만, v0.106.0부터 deprecated된 Claude Opus 4.1이 제거된 것이 확인되었습니다 . model= 문자열 리터럴을 grep하고 v0.109.2 기준으로 strict 모드에서 mypy를 실행하세요. 누락된 Literal 멤버가 런타임 전에 타입 오류로 나타납니다.

2026년 6월 기준으로 프로덕션에서 claude-fable-5를 호출할 수 있나요?

아니요. 2026년 6월 12일 오후 5시 21분(ET 기준) 발효된 미국 정부 수출통제 지침에 따라 Anthropic은 모든 고객을 대상으로 Claude Fable 5 및 Claude Mythos 5 접근을 중단했으며, 다른 모델은 영향을 받지 않았습니다 . SDK 코드는 존재하지만, 중단 기간 중에는 API가 해당 모델 ID를 거부합니다. 복원 여부는 Anthropic의 상태 업데이트를 모니터링하세요.

Managed Agents를 사용하지 않는다면 v0.109.0으로 업그레이드해야 하나요?

해당 릴리스만을 위해서라면 불필요합니다. v0.109.0은 Managed Agents 배포 API와 환경 변수 인증만 추가합니다 . 하지만 v0.109.1(frontier_llm 거부 카테고리)과 v0.109.2(은퇴 식별자 제거)까지 진행하는 것은 별도로 권장됩니다. 거부 응답 인식 코드의 최소 안전 핀은 ≥v0.109.1입니다 .

v0.108.0 이후 버전에서 거부 응답을 올바르게 처리하는 방법은?

API 호출 후마다 message.stop_reason을 확인하세요. "refusal"인 경우 message.stop_details.categorycyber, bio, frontier_llm, reasoning_extraction 중 하나 — 를 읽어 폴백 모델로 재시도할지, 거부를 호출자에게 전달할지 결정하세요 . 거부된 요청은 출력이 생성되기 전에는 과금되지 않습니다 .