Claude API streaming_error (api_error): 원인과 해결법
Claude API streaming_error api_error는 SSE 스트림이 중간에 끊기거나 malformed event 발생에 발생합니다. 스트리밍 응답 중단이며, exponential backoff 재시도가 효과적해야 합니다. 이 글은 5가지 흔한 원인과 Python/TypeScript 코드 예시를 다룹니다.
전반적인 Claude API 에러 처리 패턴은 Claude API Error Handling 가이드를 참고하세요.
무엇을 의미하는가?
streaming_error 에러 서브타입는 SSE 스트림이 중간에 끊기거나 malformed event 발생을 의미합니다. Anthropic API의 에러 응답 본문에는 error.type이 "api_error"로 명시되며, error.message에 구체적 사유가 옵니다.
응답 예시:
{
"type": "error",
"error": {
"type": "api_error",
"message": "..."
}
}
흔한 원인 5가지
- 긴 응답 중 connection timeout (>60s)
- Proxy/firewall이 SSE long-polling 차단
- Client 측 부적절한 stream parsing
- Bedrock 사용 시 streaming format 불일치
해결 코드 (Python)
# Resume from last text on stream error
def resilient_stream(client, model, messages, max_tokens=4096):
accumulated = ""
for attempt in range(3):
try:
with client.messages.stream(
model=model, messages=messages, max_tokens=max_tokens,
) as stream:
for text in stream.text_stream:
accumulated += text
yield text
return
except (anthropic.APIError, ConnectionError) as e:
if attempt == 2:
raise
# Send accumulated as continuation
messages = messages + [
{"role": "assistant", "content": accumulated},
{"role": "user", "content": "이어서 작성해주세요"}
]
해결 코드 (TypeScript)
async function* resilientStream(client, opts) {
let accumulated = "";
for (let attempt = 0; attempt < 3; attempt++) {
try {
const stream = await client.messages.stream(opts);
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
accumulated += event.delta.text;
yield event.delta.text;
}
}
return;
} catch (e: any) {
if (attempt === 2) throw e;
opts = { ...opts, messages: [
...opts.messages,
{ role: "assistant", content: accumulated },
{ role: "user", content: "Continue" },
]};
}
}
}
재시도 전략
이 에러는 재시도 가능합니다. Exponential backoff 권장 시퀀스:
attempt 1 → wait 1s
attempt 2 → wait 3s
attempt 3 → wait 8s
attempt 4 → wait 20s
attempt 5 → wait 45s (final)
응답 헤더의 retry-after가 있으면 그 값을 우선 사용하세요.
비용 영향
재시도 시 매번 input 토큰이 다시 청구됩니다. 재시도 횟수 × 입력 토큰 = 추가 비용. Prompt caching을 적용하면 재시도 비용을 90%까지 절감할 수 있습니다.
자세한 비용 절감 패턴은 Claude API Cost and Prompt Caching Break-Even 또는 무료 비용 계산기를 참고하세요.
관련 에러
- 400 invalid_request_error — 잘못된 요청 형식
- 401 authentication_error — 인증 실패
- 403 permission_error — 권한 부족
- 429 rate_limit_error — Rate limit 초과
- 529 overloaded_error — API 일시 과부하
자주 묻는 질문
streaming_error 에러가 떴을 때 비용이 청구되나요?
처리되지 않은 요청은 청구되지 않습니다. 단, 재시도 후 성공한 요청은 정상 청구됩니다.
streaming_error와 다른 에러의 차이는?
streaming_error는 일시적/서버 측 이슈로 재시도가 효과적입니다. 반면 4xx 클라이언트 에러 (400/401/403/404)는 요청 자체에 문제가 있어 재시도해도 동일한 결과가 나옵니다.
Bedrock/Vertex에서도 같은 에러 코드인가요?
네, Anthropic의 error.type 명명 규칙은 모든 deployment (Direct API, AWS Bedrock, GCP Vertex AI)에서 동일합니다. 다만 HTTP 상태 코드는 platform 별로 wrapping되어 다를 수 있습니다 (예: Bedrock은 에러 type을 다른 prefix로 변경).
다음 단계
- 프로덕션 코드에 retry 로직을 추가하려면 Production Patterns for Claude Agents를
- 비용을 모니터링하려면 Claude API 비용 모니터링 가이드를
- 에러 분류 자동화는 무료 /cheatsheet-한국어에서 30개 프롬프트로
에러 처리 패턴 30개 + Pydantic 검증 코드 — Claude API Cost Optimization 마스터클래스 ($59)에 retry 미들웨어, 비용 가드레일, 에러 알림 패턴 12편 포함.