
Claude Code의 WebSearch가 갑자기 400 에러를 반환함 ── 범인은 API 측의 사이런트 사양 변경이었다
요약
Claude Code의 WebSearch 기능이 Opus 4.8 모델에서 400 에러를 반환하는 현상을 분석했습니다. 이는 API 측의 사전 공지 없는 사양 변경으로 인해 'thinking 비활성화'와 'xhigh effort' 설정이 충돌하며 발생한 문제입니다.
핵심 포인트
- Opus 4.8 모델에서 xhigh effort 사용 시 WebSearch 에러 발생
- API 측의 사이런트 사양 변경으로 인한 유효성 검사 강화가 원인
- 문서에 명시되지 않은 제약 사항이 에러 메시지를 통해 확인됨
- 해결책으로 검색 작업을 Sonnet 모델 기반의 에이전트에 위임하는 방식 권장
서론
오늘 아침 가드(guard)를 세 번이나 다시 만든 경위를 공개했지만, 바로 그날 깔끔한 결말이 났기에 단편으로 남겨둔다. 수개월 동안 아무 문제 없이 작동하던 Claude Code의 WebSearch가, 코드도 설정도 아무것도 바꾸지 않았는데 갑자기 400 에러를 반환하기 시작한 이야기다.
에러 전문은 다음과 같다.
API Error: 400 output_config.effort 'xhigh' is not supported
when thinking is disabled on this model.
Use effort 'high' or below, or enable thinking.
발생 조건이 묘하게 한정적인데, Opus 4.8 × effort xhigh 세션에서 WebSearch를 사용했을 때만 에러가 발생한다. 세션 본체의 대화나 파일 조작은 정상적으로 작동하는데, 검색만 반드시 실패한다.
격리: thinking 설정은 전멸, Sonnet은 무사함
에러 문구대로라면 "thinking을 활성화하면 통과할" 것이므로, 우선 재현시킨 뒤 설정을 차례대로 시도해 보았다. 헤드리스 실행(claude -p)으로 동일한 프롬프트를 흘려보낸 결과는 다음과 같다.
| # | 조건 | 결과 |
|---|---|---|
| 1 | Opus 4.8 × xhigh (순정 상태) | 400 |
| ... |
thinking을 활성화하는 모든 수단이 통하지 않았다. 여기서 구조가 보인다. WebSearch는 Claude Code가 내부적으로 발행하는 별도의 API 요청으로서 실행되며, 그 요청이 thinking이 비활성화된 상태로 고정된 채 세션의 effort를 상속받고 있다. 세션 측에서 thinking을 켜더라도 내부 요청에는 전파되지 않기 때문에, 설정으로는 회피할 수 없는 것이다.
Opus 4.8에서만 발생하는 데에도 이유가 있다. 현재의 주요 모델 중 thinking을 생략했을 때 "비활성화"되는 것은 Opus 4.8이며, Fable 5는 항상 켜져 있고, Sonnet 5는 생략 시 자동으로 켜진다. "thinking 비활성화 × xhigh"라는 조합에 들어갈 수 있는 것이 Opus뿐이라는 이야기였다.
언제 바뀌었나: 며칠 만에 문서가 새로 작성되어 있었다
이 부분이 이번에 가장 쓰고 싶었던 부분이다. 이 400 에러는 7월 중순까지 존재하지 않았다.
확신을 가지고 말할 수 있는 것은, 7월 20일 시점의 effort 공식 문서를 확인해 둔 기록이 수중에 있기 때문이다. 당시 기술은 "effort는 thinking의 활성화를 요구하지 않는다"였으며, 이 제약에 대한 언급은 없었다. 그런데 며칠 뒤인 오늘 확인해보니, 문서는 이 제약과 일치하는 내용으로 바뀌어 있다. API 측에 유효성 검사(validation)가 추가되었고, 문서도 비슷한 시기에 업데이트되었다 —— 공식 발표는 찾을 수 없으므로, 이른바 사이런트 사양 변경(silent specification change)이다.
솔직히 고백하자면, 나는 이 에러 설명을 처음 보았을 때 "공식 문서에 기재되어 있지 않다"는 것을 이유로 오보라고 판단하여 버렸다. 문서는 "있다"는 증명에는 쓸 수 있지만 "없다"는 증명에는 취약하다. 실제로 반환된 에러 메시지의 전문이야말로 가장 강력한 1차 증거이며, 문서와 모순된다면 "미기재된 새로운 제약"을 제1가설로 세웠어야 했다. 이 교훈까지 포함하여 기사로 남겨둔다.
워크아라운드(Workaround)는 단 한 줄
대처법은 허무할 정도다. 프로젝트의 CLAUDE.md에 한 줄을 추가했을 뿐이다.
WebSearch는 주 세션에서 직접 호출하지 않는다. 웹 검색이 필요할 때는
effort를 낮추지 말고, Agent 도구(general-purpose・model: sonnet)에
검색만 위임하여 결과를 받는다.
Sonnet 5는 이 제약을 받지 않으므로, 검색만 서브 에이전트(sub-agent)로 넘기면 effort xhigh인 본체는 그대로 유지할 수 있다. 공유 폴더에서 여러 명이 동일한 프로젝트를 사용하는 경우에도, CLAUDE.md에 적어두면 모두에게 한 번에 적용된다. 향후 Claude Code 측에서 내부 요청 형식을 수정한다면, 이 줄을 지우는 것만으로 원래대로 돌아온다.
마치며
court 루프, 모델 가드(model guard)의 경위, 그리고 이번 사례까지, 지난 2개월 동안 배운 것은 결국 같은 형태를 띠고 있다. LLM 위에 구축한 운영은, 내가 아무것도 바꾸지 않아도 망가진다. 토대인 모델과 API가 월 단위로 움직이고 있기 때문이다.
따라서 「작동하고 있다」는 것을 영구적인 것으로 생각하지 말고, 고장 난 날에 최단 시간으로 복구하기 위한 패턴을 갖춰 두어야 한다. 최소한의 재현을 만들고, 어느 계층(layer)의 변경인지 분리하며, 회피 방법을 규칙으로 작성하여 수평 전개한다. 이번에는 이 패턴 덕분에 원인 특정부터 워크아라운드 (workaround) 배포까지 30분 만에 끝났다. 수개월 동안 아무 문제 없던 시스템이 어느 날 갑자기 망가지는 것은, LLM API 운영에서는 아마 「이상 현상」이 아니라 「계절적 변화」와 같은 것이다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기