Skip to main content

과금 우선: write_response_body_failed 500은 과금되지 않습니다

게이트웨이가 500write_response_body_failed / connection reset by peer와 함께 반환하면, 플랫폼은 이미 내부적으로 2-3회 재시도한 뒤 모두 실패했을 때만 오류를 표시합니다. 이 요청에는 전혀 과금되지 않습니다.따라서 로그가 이러한 오류로 가득 차더라도 청구서에 대응하는 과금은 나타나지 않습니다 — 실패에 대해 비용을 지불하는 것이 아닙니다. 다른 경우는 과금됩니다 (클라이언트가 너무 일찍 종료하는 경우)이며, 아래의 “Billing 영향” 섹션을 보십시오.
짧은 답변: image API 응답은 일반적으로 10MB에서 수십 MB까지이며, 끊김은 거의 항상 응답을 다운로드하는 동안 발생합니다(요청 본문이 너무 커서가 아닙니다 — 일반 텍스트-to-image에서도 끊깁니다). 먼저 콘솔 로그가 어느 범주에 해당하는지 확인한 다음, 아래의 macOS / Linux / Node.js 자체 점검을 실행하십시오.

오류의 모습

같은 근본 원인이 읽는 쪽에 따라 완전히 다른 두 가지 얼굴로 나타납니다.

게이트웨이에서

클라이언트에서

Node.js에서는 “killed”와 “closed”를 구분해야 합니다: ECONNRESET은 TCP RST가 도착했다는 뜻입니다. 즉, 경로상의 어떤 지점에서 연결이 killed되었고, 네트워크 홉을 가리킵니다. SocketError: other side closed / ERR_STREAM_PREMATURE_CLOSE는 상대가 정상적으로 닫았다는 뜻(FIN)으로, 누락된 chunked terminator 같은 서버 측 마무리 문제를 가리킵니다. 이 둘은 완전히 다른 방향을 가리키므로 하나의 증상으로 취급해서는 안 됩니다.또한, UND_ERR_*은 undici(Node 18+의 내장 fetch를 구동하는 엔진)에서만 나올 수 있는 반면, read ECONNRESET은 libuv의 최상위 표현이며, axios / node-fetch / http 모듈이 모두 생성합니다. 두 종류가 함께 나타난다면 먼저 앱에 서로 다른 HTTP 경로가 두 개 있는지 확인하십시오 — 그 경우에는 아예 같은 사고가 아닙니다.

먼저 방향을 확인하십시오: 누가 끊었는지

write_response_body_failed 코드는 핵심 단서입니다 — 이는 게이트웨이가 응답 본문을 호출자에게 다시 쓰는 도중 실패했음을 의미합니다. 이는 업스트림 모델 오류가 아니라 다운스트림 방향입니다. 결과는 이미 생성되어 있었고, 사용자에게 전달되는 도중 연결이 끊겼습니다.
이는 지나치게 큰 요청 본문 때문에 발생한 것이 아닙니다. 이미지 편집 업로드는 참조 이미지를 전송하므로 업로드 크기를 의심하기 쉽지만, 요청 본문이 몇백 바이트에 불과한 일반 text-to-image도 똑같이 자주 실패합니다. 문제는 응답을 내려받는 과정에 있습니다. 이미지 payload는 10MB에서 수십 MB까지 이르며, 전체 경로에서 가장 취약한 구간입니다.

다운스트림 끊김

write_response_body_failed, connection reset by peer, 클라이언트 측 SSL EOF. 게이트웨이가 본문을 전송하던 중 연결이 사라졌습니다. 플랫폼이 이에 대해 500을 반환하더라도 과금되지 않습니다 — 아래의 billing 섹션을 참조하십시오.

업스트림 실패(채널 측)

업스트림 타임아웃, upstream_error, 업스트림 payload를 담은 5xx, 또는 비정상적인 finishReason를 동반한 HTTP 200. 이는 진짜 채널 문제입니다 — x-request-id를 지원팀에 전달하십시오.

가장 강한 신호: 콘솔 로그가 이 호출에 대해 말해 주는 것

다른 무엇보다 먼저 콘솔의 호출 로그를 확인하십시오. 비용이 들지 않으며, 어떤 클라이언트 측 단계보다 빠르게 범위를 좁혀 줍니다:
여기서 사람들이 자주 거꾸로 이해하는 결론이 나옵니다: UND_ERR_CONNECT_TIMEOUT 같은 연결 단계 실패는 과금을 발생시킬 수 없습니다, 요청이 게이트웨이까지 도달하지 않았기 때문입니다. 따라서 “연결 타임아웃이 많이 발생한다”와 “과금이 많이 발생한다”가 동시에 보인다면, 그것들은 절대 같은 요청이 아닙니다 — 하나의 근본 원인으로 모두 설명하려 하지 말고 별도로 조사하십시오.

자신을 배제하는 네 단계

순서대로 확인하십시오. 대부분의 경우 처음 두 단계에서 해결됩니다:
1

애플리케이션 계층의 오독을 배제하십시오: 실제로 받았지만 유지하지 못했을 수 있습니다

“이미지를 받지 못했다”는 보통 코드가 예외를 던지고 “request failed”로 잡힌 뒤 내린 결론입니다 — 바이트가 전혀 도착하지 않았다는 증거가 아닙니다. 가장 흔한 사례는 gpt-image-2-all가 기본적으로 b64_json를 반환하면서 data: 접두사가 없다는 점입니다. 그래서 data[0].url를 읽는 코드가 undefined를 얻고, downstream에서 예외를 던지며, 실패로 판정되고, 재시도가 발생합니다 — 그 과정에서 다시 과금됩니다.증상은 네트워크 장애와 동일하지만, 네트워크 장애가 실제로 필요한 것은 아닙니다. 한 줄만 출력해서 확인하십시오:
시리즈별 필드와 접두사 차이는 base64 접두사 참고에 있습니다.
2

모든 채널과 모델이 동시에 실패하는지 확인하십시오

서로 다른 두 채널에서 서로 다른 두 모델을 실행했는데 같은 시간대에 모두 같은 오류를 낸다면, 채널별 원인은 사실상 배제됩니다 — 업스트림이 그렇게 깔끔하게 동시에 실패하지는 않습니다.
3

클라이언트 런타임을 확인하십시오: TLS 스택(Python) 또는 undici 타임아웃(Node.js)

Python: TLS 스택 버전을 확인하십시오. Node.js: undici의 세 가지 타임아웃을 확인하십시오. 두 내용은 다음 두 섹션에서 다룹니다. 실무에서 가장 흔한 근본 원인이며, 완전히 사용자 머신 안에 있고, 한 번의 명령으로 확인됩니다.
4

동시 실행 수를 낮추고, 순차 실행으로 전환하고, 로컬 프록시를 끄십시오

VPN 또는 프록시를 끈 상태에서 동일한 요청을 동시 실행 수 1-2로 다시 실행하십시오. 그렇게 했을 때는 절대 재현되지 않는다면, 문제는 채널이 아니라 클라이언트의 연결 처리, 로컬 리소스(연결 풀, 파일 디스크립터, 메모리), 또는 네트워크 경로에 있습니다.

가장 유력한 용의자: 클라이언트 TLS 스택(특히 macOS에서)

macOS에 포함된 Python(/usr/bin/python3)은 LibreSSL 2.8.3에 링크되며, OpenSSL은 아닙니다. urllib3 v2와 결합되면, 그 조합은 대용량 응답 본문의 동시 다운로드 중에 SSLEOFError를 안정적으로 발생시킵니다. 클라이언트가 일방적으로 연결을 끊고, 게이트웨이는 이에 따라 connection reset by peer를 대량으로 기록합니다.

확인할 명령 하나

requests을 import할 때 이 경고가 보인다면 같은 신호입니다:

해결: 인터프리터를 전환하십시오

urllib3를 내리지 마십시오 — 대신 올바른 OpenSSL로 빌드된 Python을 사용하십시오:

측정 비교 (2026-07-29, UTC+8)

두 채널 비교 테스트에서 얻은 실제 수치입니다. Nano Banana 시리즈(gemini-3-pro-image / gemini-3.1-flash-image) 기준입니다: 결론은 명확합니다: 인터프리터를 바꾸면서 한 자릿수 자릿수의 차이가 났고, 그 이전에 두 채널이 함께 실패했다는 사실만으로도 원인이 채널 문제가 아님이 이미 입증되었습니다.

리눅스 서버에서 확인할 것(완전히 다른 목록)

위의 TLS 스택 검사는 사실상 모든 리눅스 머신에서 통과합니다 — 배포판 Python은 일반 OpenSSL에 링크되므로 그곳에는 LibreSSL 함정이 없습니다. 그 검사에서 멈추면 안 됩니다. 서버 측 문제는 egress 경로컨테이너 제한에 있으며, 이는 로컬 개발과는 완전히 다른 세계입니다.

1. 클라우드 NAT 게이트웨이와 로드 밸런서의 유휴 시간 제한(서버 측의 가장 큰 원인)

이는 운영 환경에서 connection reset by peer의 가장 큰 원인입니다. AWS NAT Gateway를 예로 들면, 이 서비스는 고정된, 설정 불가능한 350초 유휴 시간 제한을 강제하며, 시간이 지나면 FIN이 아니라 RST를 보냅니다 — 따라서 클라이언트가 보는 현상은 정확히 ECONNRESET입니다. 문제는 이것이 연쇄적으로 번진다는 점입니다. 풀에 있는 연결이 350초를 넘겨 유휴 상태가 되면 모두 죽어버리므로, 요청이 첫 번째 연결에서 RST를 받으면 클라이언트는 다음 풀 연결로 투명하게 재시도합니다 — 그 연결도 똑같이 유휴 상태여서 역시 RST를 받습니다. 특징은 “한동안 조용하다가, 몇몇 호출이 연달아 실패하고, 그다음에는 다시 모두 정상으로 돌아오는” 패턴입니다.
이는 Node.js 섹션의 “keep-alive가 죽은 연결을 다시 사용하는” 사례와 같은 메커니즘입니다 — 서버에서는 범인이 보통 로컬 프록시 소프트웨어가 아니라 클라우드 제공업체의 NAT 게이트웨이입니다.
해결 방법(아무거나 가능하며, 앞의 두 가지를 권장합니다):
  • TCP keepalive를 350초 미만으로 설정하여 조용한 구간에도 트래픽이 흐르도록 합니다;
  • 연결이 풀에서 유휴 상태로 머무를 수 있는 시간을 제한하여 죽었을 가능성이 있는 연결을 버리도록 합니다(Node: new Agent({ keepAliveTimeout: 60_000 }); Python requests: HTTPAdapter를 통해 풀을 구성합니다);
  • NAT 게이트웨이를 완전히 우회합니다. 예: VPC endpoints를 사용합니다.
다른 클라우드와 자체 호스팅 로드 밸런서는 다른 유휴 값을 사용하지만, 접근 방식은 동일합니다. 경로에서 가장 짧은 유휴 시간 제한을 찾아 keepalive를 그보다 낮게 설정하면 됩니다.

2. TCP keepalive 기본값은 사실상 “꺼짐”입니다

Linux는 tcp_keepalive_time을 기본적으로 **7200초(2시간)**로 설정하는데, 이는 위의 어떤 유휴 시간 제한보다도 훨씬 길어서 실제로는 쓸모가 없습니다.
HTTP 클라이언트 자체에서 keepalive를 켜는 방식이 더 견고한 접근입니다. 컨테이너에서는 커널 매개변수를 바꿀 수 없는 경우가 많기 때문입니다.

3. 컨테이너 네트워크 MTU

Docker / Kubernetes 오버레이 네트워크(flannel VXLAN과 그 외 유사한 방식)는 흔히 1500이 아니라 1450 MTU로 동작합니다. 여기에 경로상의 PMTUD 블랙홀까지 겹치면, 전형적인 “작은 요청은 항상 정상, 큰 응답은 항상 멈춤” 현상이 발생합니다.

4. 컨테이너 메모리 제한 -> 프로세스가 OOMKilled됨

4K base64 페이로드 하나만으로도 20-30MB에 이를 수 있습니다. 이를 resp.json()로 통째로 읽고 동시에 여러 요청이 들어오면 컨테이너 메모리 제한을 쉽게 초과하고, 커널이 프로세스를 종료합니다 — 이 역시 “연결이 그냥 끊어졌다”로 보입니다:
해결 방법은 아래의 “응답을 통째로 읽지 말고 스트리밍하라”를 참고하십시오.

5. 프록시 환경 변수(서버에서 가장 교묘한 원인)

서버에는 종종 HTTP_PROXY / HTTPS_PROXY / NO_PROXY 값이 /etc/environment, systemd 유닛, 또는 Dockerfile에 전역으로 설정되어 있습니다 — 누가 설정했는지도 잊힌 채 남아 있는 경우가 많습니다. 더 문제는, 언어마다 이를 존중하는 방식이 다르다는 점입니다: 그 불일치는 정말로 혼란스러운 결과를 만듭니다. 한 머신에서는 curl과 Python이 프록시를 거치는데 Node는 직접 연결되거나, 그 반대가 되기도 해서 서로 결과가 달라지고, 문제 해결 과정에서 서로 모순되는 결론이 나옵니다. 먼저 확인하십시오:
APIYI는 직접 접근 가능하므로, 서버에서는 일반적으로 api.apiyi.comNO_PROXY에 두는 것이 좋습니다 — 아니면 아예 프록시 변수를 두지 않아도 됩니다.

서버 측 일회성 자가 점검

Node.js: SDK의 timeout가 닿지 못하는 세 가지 독립적인 타임아웃

Node 18+의 내장 fetch는 undici 위에서 동작하며, 요청의 세 단계를 다루는 세 가지 독립적인 타임아웃이 있습니다. “timeout을 5분으로 설정했는데요”라는 말은 보통 그 셋 중 어느 것도 아닌 네 번째 값을 바꿨다는 뜻입니다.
openai-node의 timeout 옵션은 AbortController 기반의 전체 요청 타임아웃이며 위의 세 가지에는 전파되지 않습니다. timeout을 60초에서 300초로 늘려도 connectTimeout은 10초로 유지됩니다. 직접 사용하는 fetch()에서의 AbortSignal.timeout()도 마찬가지입니다.“timeout이 엄청 큰데도 여전히 timeout이 난다”는 상황의 가장 흔한 이유는 잘못된 계층을 조정했기 때문입니다.

올바른 설정

undici의 세 타임아웃을 늘리려면 전역 또는 요청별 Agent가 필요합니다:

maxRetries는 기본값이 2이며 연결 오류를 자동으로 재시도합니다

openai-node는 기본적으로 maxRetries: 2를 사용하며, 연결 오류와 타임아웃 모두가 해당 자동 재시도 범위에 포함됩니다. 따라서 하나의 논리적 호출이 코드에 재시도 로직이 전혀 없어도 실제 요청 세 번을 만들어낼 수 있습니다(각 요청이 과금되는지는 어떤 “과금 영향” 범주에 속하는지에 따라 달라집니다). 이미지 엔드포인트는 비용이 큰 동기식 장기 요청이므로, 항상 maxRetries: 0을 명시적으로 설정하고 재시도 로직도 직접 관리하십시오, 자체 backoff와 시도 상한을 두고 운영해야 합니다. 과금 규칙은 Retry Strategy에 있습니다.
먼저 실제로 어떤 스택을 사용 중인지 확인하십시오: node -v, npm ls openai undici axios node-fetch. UND_ERR_* 코드만으로는 아래에 undici가 있다는 사실만 증명할 뿐이며, OpenAI SDK를 사용하고 있다는 사실은 증명하지 못합니다. 직접 사용하는 fetch()도 같은 코드를 던지며, 순수한 fetch()에는 maxRetries이 전혀 없습니다.

이미 죽은 연결을 재사용하는 keep-alive

undici는 기본적으로 keep-alive로 연결 풀링을 사용합니다. VPN, NAT 또는 proxy가 유휴 연결을 조용히 회수해도 클라이언트는 이를 알지 못한 채 다음 요청에서 그 연결을 풀에서 꺼내게 됩니다 — write가 즉시 RST를 받으며 read ECONNRESET로 나타납니다. 이것은 호출 간격이 벌어질 때 ECONNRESET의 가장 흔한 원인이며, “오류가 한 시간 구간에 몰린다”와 “첫 번째 재시도조차 실패한다”를 모두 설명합니다. 재사용을 비활성화하여 확인하십시오:

로컬 프록시 / VPN: 이미지 엔드포인트가 먼저 드러내는 홉

APIYI는 중국 본토 내부에서 직접 접근 가능하며 프록시나 VPN이 필요 없습니다 (API를 사용하려면 프록시가 필요합니까? 참조). 따라서 프록시를 끄고 다시 테스트하는 것이 가장 저렴하고 정보량이 많은 단일 단계입니다.다만 분명히 하자면, 프록시는 단지 가장 큰 의심 변수일 뿐, 확정된 근본 원인은 아닙니다. 아래 매트릭스가 실제로 장애를 특정합니다.
두 가지 특성 때문에 이미지 엔드포인트는 텍스트 엔드포인트보다 훨씬 더 민감합니다. 생성 중 30~60초 동안 바이트가 전혀 흐르지 않는 점, 그리고 MB 규모의 본문이 한 번에 전달되는 점입니다. 채팅 엔드포인트는 정상인데 이미지 엔드포인트만 실패한다면, 대개 이 둘 중 하나입니다.

fake-ip / 라우팅 규칙 누락

프록시의 fake-ip 모드에서 규칙이 누락되면 라우팅 불가능한 주소인 198.18.x.x로 연결되어 정확히 10초짜리 연결 시간 초과가 발생합니다. 이것은 “연결이 느림”이 아니라는 점에 유의하십시오. 아예 경로가 없으므로 connect.timeout를 올려도 해결되지 않습니다. 실제로 도달한 remote_ip를 항상 기록해야 합니다.

생성 중 유휴 연결로 회수됨

요청이 전송된 뒤 30~60초 동안 바이트가 전혀 흐르지 않으면, 프록시가 자신의 유휴 정책에 따라 연결을 회수합니다. 특징은 이미지 크기와 무관하게 실패 시각이 딱 떨어지는 수치 — 30 / 60 / 120초 — 에 맞아떨어진다는 점입니다.

MTU / PMTUD 블랙홀

ICMP “fragmentation needed”가 드롭되는 동안 터널 MTU가 경로 MTU보다 낮으면 PMTUD가 깨집니다. 전형적인 특징은 작은 요청은 항상 정상이고 큰 응답은 항상 멈춘다는 점이며, 수신된 바이트가 몇 KB에서 수십 KB 수준에 고정됩니다. 터널 MTU를 약 1400으로 낮추면 보통 해결됩니다.

MITM 복호화 및 전체 버퍼링

HTTPS 복호화가 활성화된 프록시는 대개 큰 본문 전체를 버퍼링하다가 크기 한도에 걸리거나, chunked를 Content-Length로 다시 쓰는 과정에서 길이를 잘못 계산해 RST를 발생시킬 수 있습니다. 이것도 MB 규모의 이미지 응답에만 영향을 주며, 텍스트 호출에는 절대 해당하지 않습니다.

진단 매트릭스

이 절의 핵심입니다. 축은 딱 두 개뿐입니다. 실패가 첫 바이트 전후 중 언제 발생했는지, 그리고 몇 바이트가 도착했는지입니다. 마지막 행이 가장 가치 있는 단일 테스트입니다. 본문을 수 MB에서 약 1KB로 줄여 줍니다. URL 모드는 일관되게 성공하는데 base64 모드는 일관되게 실패한다면, 문제는 전송량에 따라 커지는 것입니다. 따라서 앞의 두 열은 곧바로 배제됩니다.

전체 타이밍 프로필을 확인하는 한 번의 명령

매트릭스와 대조해 읽으십시오. connect 값이 없으면 연결 단계입니다. ttfb가 없고 total가 딱 떨어지는 수치면 유휴 회수입니다. 전체 bytes가 있지만 total ≈ ttfb + 300curl: (18)가 함께 나타나면 종료자가 누락된 것입니다. bytes가 수십 KB에서 멈춰 있으면 MTU 문제입니다.
프록시 켬과 프록시 끔을 A/B 테스트할 때는 실행을 번갈아 수행해야 하며 — 절대로 한꺼번에 묶지 마십시오. 프록시를 사용한 실행 5회 뒤에 직접 실행 5회를 붙이면 시간대 기반 장애가 결과를 오염시켜 완전히 잘못된 결론으로 이어질 수 있습니다. 실제로 모두 실패했다가 몇 분 뒤에는 모두 성공하고, 다시 실패하는 구간을 측정한 적이 있습니다. 대신 proxy → direct → proxy → direct을 실행하고, 매번 remote_ip를 기록하십시오.

기타 흔한 트리거

실행 중인 작업이 중간에 강제 중단될 때

디버깅 중 Ctrl+C를 누르거나, 프로세스를 재시작하거나, hot reload를 하거나, 실행 중인 스크립트를 종료하면 — 전송 중인 모든 대형 응답은 게이트웨이에 write_response_body_failed를 남깁니다. 이것은 가장 자주 “채널이 불안정하다”로 오해되는 오경보입니다.

외부 타임아웃이 먼저 발생할 때

작업 큐 워커 타임아웃, 서버리스 실행 제한, 게이트웨이/CDN 오리진 타임아웃(일반적으로 기본값은 60초입니다). 생성 시간보다 짧은 어느 계층이든 먼저 연결을 끊습니다 — 반드시 읽기 및 모범 사례를 참고하십시오.

커넥션 풀과 과도한 동시 실행 수

커넥션 풀 상한, 로컬 파일 디스크립터 제한, NAT/방화벽이 장시간 유지되는 연결을 조용히 회수하는 경우입니다. 대형 응답은 훨씬 더 오래 열린 상태로 유지되므로 텍스트 엔드포인트보다 이러한 제한에 훨씬 더 자주 걸립니다.

응답 본문이 메모리를 소진할 때

단일 4K base64 페이로드는 20-30MB에 이를 수 있습니다. 동시 실행 수가 높은 상태에서 resp.json()로 이를 한꺼번에 로드하면 컨테이너 메모리가 고갈되어 프로세스가 OOM-killed될 수 있으며 — 이 역시 “아무 이유 없이 연결이 끊겼다”로 나타납니다.

과금 영향: 어떤 경우는 비용이 발생하고 어떤 경우는 발생하지 않는가

이 두 상황은 늘 혼동되지만, 실제 과금 방식은 정반대입니다:

플랫폼이 500 write_response_body_failed를 반환함 — 과금되지 않습니다

이 오류는 게이트웨이가 이미지 데이터를 사용자에게 다시 쓰는 중 연결이 끊겼음을 의미합니다. 플랫폼은 내부적으로 자동 재시도를 2~3회 수행하며, 그 모든 시도가 실패한 뒤에야 500을 반환합니다.이 경우에는 비용이 발생하지 않습니다. 같은 요청에서 이런 오류가 여러 번 연속으로 발생해도 청구서에는 이에 대응하는 과금 내역이 남지 않습니다 — 이런 실패에 대해서는 절대 비용을 지불하지 않습니다.

클라이언트가 먼저 종료함 — 정상 과금됩니다

다른 경우는 게이트웨이가 전송을 완료하기 전에 사용자 측에서 먼저 연결을 끊는 경우입니다. 예를 들어 클라이언트 타임아웃이 발생하거나, 디버깅 중 Ctrl+C를 누르거나, 프로세스를 재시작하거나, OOM kill이 발생하는 경우입니다.서버와 상위 단계에서의 생성은 이미 완료된 상태이므로, 이런 경우는 정상 과금됩니다 — “이미지를 받지 못했다”는 것이 “과금되지 않았다”는 뜻은 아닙니다. 문제를 확인하는 동안 큰 이미지 요청을 반복하면 실제로 꽤 큰 청구가 발생할 수 있습니다.
둘을 구분하는 방법은 바로 위 표와 같습니다: 콘솔에 정상 호출이 기록되었는지, 아니면 500 write_response_body_failed가 기록되었는지 확인하십시오. 따라서 재시도 정책도 그에 맞게 엄격하게 유지해야 합니다: 전송 계층 수준의 실패는 재시도할 가치가 있지만, 각 재시도는 별도로 과금되는 호출일 수 있습니다(어느 범주에 해당하느냐에 따라 다릅니다). 무제한 재시도 루프는 절대 작성하지 마십시오.

올바르게 재시도하는 방법

핵심 규칙: 전송 계층 예외만 재시도하고, HTTP 수준 오류는 절대 재시도하지 마십시오. 4xx를 만 번 다시 보내도 여전히 4xx이며, 시간만 낭비합니다.
모든 시도를 각각 기록하십시오(위의 attempts 목록). 그렇지 않으면 클라이언트 재시도가 성공해도 로그에는 깔끔한 200만 남고, 전송이 실제로 몇 번이나 깨졌는지 결코 알 수 없습니다. 그 데이터는 채널 품질을 평가할 때 필수이며, 자신의 재시도를 채널 동작으로 오해하는 일을 막아 줍니다.

응답 전체를 로드하지 말고 스트리밍하십시오

큰 본문은 stream=True로 청크 단위로 읽으십시오. 이렇게 하면 최대 메모리 사용량을 낮게 유지할 수 있고, 전송의 어느 단계에서 정확히 끊겼는지 확인할 수 있습니다:

정말로 지원팀에 문의할 가치가 있을 때

자체 점검을 모두 마쳤다면, 다음 중 어느 하나라도 해당하면 에스컬레이션하십시오.
  • 올바른 OpenSSL 인터프리터로 전환하고 직렬 실행으로 낮춘 뒤에도 여전히 안정적으로 재현됩니다;
  • 같은 시간대에 다른 항목들은 정상인데 특정한 하나의 채널 또는 모델만 실패합니다;
  • 응답 본문이 완전히 도착했지만(바이트 수가 Content-Length와 일치함) 연결이 timeout으로 종료될 때까지 닫히지 않습니다. 이는 상위 계층의 chunked terminator 누락으로, 채널 측 문제입니다;
  • 오류가 분명하게 업스트림 측을 향합니다(upstream_error, 원시 업스트림 5xx).
티켓에는 x-request-id, 호출 시간(시간대 포함, 예: 2026-07-29 14:32 (UTC+8)), 모델 이름, imageSize 같은 주요 매개변수, 원시 클라이언트 예외, 그리고 이미 완료한 자체 점검 단계를 포함하십시오.

관련 문서

반드시 읽어야 할 내용 및 모범 사례

동기 호출, 모델별 타임아웃, base64 처리, 연결 끊김 과금

비동기 큐를 직접 구축하기

동기 호출을 작업 큐로 감싸고 재시도를 통해 간헐적인 실패를 흡수합니다

프록시가 필요합니까?

APIYI는 프록시 없이 직접 연결되며, 인증서와 DNS 문제를 자체 점검합니다

Gemini 이미지 오류 처리

Gemini 이미지 생성의 오류 코드와 finishReason 처리