{"id":"IL-0515","org":"Python Software Foundation","date":"2026-08-15","docs":[],"title":{"en":"Downloads from files.pythonhosted.org failed with intermittent 502 and 503 errors for two weeks, breaking PyPI installs","ko":"files.pythonhosted.org 에서 파일을 받을 때 2주 가까이 502 와 503 이 간헐적으로 나서 PyPI 설치가 실패했다"},"domain":["networking"],"impact":{"scope":"Downloads from files.pythonhosted.org and therefore installations from PyPI","users":"some PyPI users","region":"Seattle-area Fastly point of presence for the Fastly fault"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"None of the PyPI configuration bugs were new; they had been in the configuration for a while and came out only when real traffic on large files with range requests forced an investigation. The 5xx baseline was already noisy, so the start of the Fastly problem was easy to miss, and part of that noise turned out to be one of the bugs.","ko":"PyPI 자체 설정의 버그는 모두 새것이 아니었고 이미 설정 안에 있었다. 범위 요청으로 큰 파일을 받는 실제 트래픽이 생기고 나서야 이 버그들을 조사하고 고쳤다. 장애 전부터 5xx 소음이 많아서 8월 15일부터 늘어난 오류를 놓치기 쉬웠고, 배경 소음으로 여기던 오류 일부가 내내 이 버그였다.\n\n글쓴이는 사용자가 문제를 피해 가지 않고 자세한 내용을 담아 보고해 준 덕분에 문제를 좁힐 수 있었다고 했다. 앞으로도 x-served-by 헤더와 시각을 담아 pypi/support 에 보고하면 더 빨리 대응할 수 있다. files.pythonhosted.org 트래픽의 많은 부분은 지난 실행과 같은 의존성을 다시 설치하는 CI 작업이고, 그중 큰 몫이 GitHub Actions 에서 온다. setup-python 의 pip, pipenv, poetry 캐시는 cache 입력으로 켜야 하고 기본값은 꺼짐이며, setup-uv 의 캐시는 GitHub 호스팅 러너의 대부분 이벤트에서 기본으로 켜져 있지만 확인해 보는 것이 좋다. 캐시된 의존성은 다음 실행에서 PyPI 에 닿지 않으므로 PyPI 나 Fastly 가 흔들릴 때 빌드가 깨질 일이 하나 줄어든다."},"related":[],"sources":[{"url":"https://blog.pypi.org/posts/2026-09-08-file-hosting-errors/","kind":"blog","archived":"https://web.archive.org/web/20261019205930/https://blog.pypi.org/posts/2026-09-08-file-hosting-errors/"}],"summary":{"en":"files.pythonhosted.org is a Fastly CDN service in front of three origins. Uploaded files are written to Amazon S3 as the durable copy and synced to Backblaze B2; on downloads Fastly tries B2 first and falls back to S3 when B2 does not answer or answers unexpectedly, and a third backend, Conveyor, serves everything that is not a package file. From 15 August 2026, a partial rollback in a Fastly canary deployment left one Seattle-area cache node with reverted caching configuration behind routing configuration that had not been reverted, and the routing layer returned 502 for traffic reaching that node. On 19 August Fastly's network operations removed a routing override that sent part of PyPI's traffic to the affected point of presence, Fastly saw recovery there on 20 August, and on 28 August Fastly patched the canary configuration bug and removed all PSF traffic, including PyPI, from its canary cohort.\n\nWhile investigating, PyPI's infrastructure engineer found older bugs in PyPI's own Fastly configuration that produced the same symptom. The fallback to S3 ran only when B2 answered with an error status; when B2 did not answer at all, Fastly synthesized its own 503 and skipped the fallback, until infra#237 added that path on 18 August. Segmented caching, used so a Range request does not pull a whole gigabyte-sized wheel into cache, cannot answer a suffix range such as bytes=-1024 or a range that starts past the end and returns a synthetic 501, and some installers read wheel metadata with suffix ranges; infra#241 on 21 August and infra#243 on 24 August exempted those requests, the second after two broken parallel downloaders generated 41,315 more errors of that class in a single day. infra#245 on 28 August moved an exemption check after URL normalization: a .metadata request with a query string had kept segmented caching on, got a 501 from the archive backend, and that response was cached and served to every later request for the same file.\n\nAfter infra#241, the 5xx count fell to two to three orders of magnitude below the pre-incident baseline, so part of what had been treated as background noise had been this bug. Downloads were fully working again from 28 August.","ko":"files.pythonhosted.org 는 세 오리진 앞에 둔 Fastly CDN 서비스다. 패키지 파일 요청은 먼저 Backblaze B2 로 가고, B2 가 답하지 않거나 예상 밖의 답을 하면 S3 로 넘어간다. 패키지 파일이 아닌 요청은 Conveyor 가 맡는다. Fastly 의 카나리 집단은 전체 배포 전에 캐시와 라우팅 소프트웨어를 먼저 받는 일부 장비이고, PyPI 트래픽은 몇 년째 여기에 들어 있었다. 카나리 배포 중 부분 롤백으로 시애틀 근처 POP 하나의 캐시 설정만 되돌아가고 라우팅 설정은 그대로 남아, 그 라우팅 계층이 캐시 노드로 가는 트래픽에 502 를 냈다. Fastly 는 이 문제가 8월 15일에 시작됐다고 봤다.\n\n8월 17일부터 사용자 보고가 쌓였고, 8월 19일의 보고가 문제를 캐시 노드 cache-pae2080020 하나로 좁혔다. 같은 날 Fastly 네트워크 운영팀이 PyPI 트래픽 일부를 그 POP 로 보내던 라우팅 재정의를 없앴고, 8월 20일에 그 POP 의 회복을 확인했다. 8월 28일 Fastly 는 카나리 설정 버그를 고치고 PyPI 를 포함한 PSF 트래픽 전부를 카나리 집단에서 뺐다.\n\n조사 중에 PyPI 자체 Fastly 설정에서 오래된 버그 셋이 같은 증상을 만들고 있었다는 것이 드러났다. 첫째, S3 로 넘기는 대체 경로는 B2 가 오류 상태 코드로 답할 때만 돌았고, B2 가 타임아웃, 연결 거부, TLS 실패로 아예 답하지 않으면 Fastly 가 스스로 503 을 만들었다. 이는 8월 18일 infra#237 로 고쳤다. 둘째, 큰 wheel 파일을 통째로 캐시에 올리지 않으려고 쓰는 segmented caching 이 bytes=-1024 같은 끝에서부터의 범위와 시작이 파일 끝을 넘는 범위를 처리하지 못하고 501 을 냈다. 일부 설치 도구는 wheel 메타데이터를 이런 범위로 읽으므로 그 읽기가 실패했다. 이는 infra#241 과 infra#243 으로 고쳤다. 셋째, segmented caching 예외 검사가 URL 정규화 전에 돌아 쿼리 문자열이 붙은 .metadata 요청에서 예외가 맞지 않았고, 잘못된 501 응답이 캐시되어 같은 파일의 뒤 요청에 모두 나갔다. 이는 8월 28일 infra#245 로 고쳤다. 8월 28일부터 다운로드는 완전히 정상으로 돌아왔다. infra#241 뒤의 오류 양은 장애 전 기준선보다 두세 자릿수 낮아서, 배경 소음으로 여기던 오류 가운데 일부가 내내 이 버그였다."},"trigger":{"en":"A partial rollback during a canary deployment inside Fastly's network, whose canary cohort had included PyPI's traffic for a number of years, left the caching configuration of one Seattle point of presence reverted while the routing configuration in front of it was not.","ko":"Fastly 네트워크 안의 카나리 배포가 부분 롤백되면서 시애틀 근처 POP 한 곳의 캐시 설정은 되돌아갔고 그 앞의 라우팅 설정은 되돌아가지 않았다. PyPI 트래픽은 몇 년째 Fastly 의 카나리 집단에 들어 있었다."},"severity":"unknown","symptoms":["high-error-rate"],"timeline":{"detected_after":"2d","resolved_after":"13d"},"date_kind":"incident","detection":{"en":"Users filed reports in the PyPI support tracker; one report isolated the 502s to a single Fastly cache node using the x-served-by headers of the failing responses.","ko":"사용자들이 PyPI 지원 트래커에 보고를 올렸다. 8월 17일에 502 가 계속 난다는 첫 보고 두 건이 열렸고, 8월 19일의 보고가 실패한 응답의 x-served-by 헤더로 문제를 캐시 노드 하나로 좁혔다. 장애 전부터 5xx 소음이 많아 PyPI 자체 지표에서는 늘어난 양이 잘 드러나지 않았다."},"components":["cdn","object-storage"],"root_cause":"dependency-failure","remediation":[{"text":{"en":"Fastly's network operations removed the routing override that sent part of PyPI's traffic to the affected point of presence","ko":"Fastly 네트워크 운영팀이 PyPI 트래픽 일부를 문제의 POP 로 보내던 라우팅 재정의를 없앴다."}},{"text":{"en":"Fixed the B2-to-S3 fallback for the case where B2 does not respond at all (infra#237)","ko":"infra#237 을 머지해 B2 가 오류로 답하지 않고 아예 답하지 않을 때도 S3 로 넘어가도록 대체 경로를 고쳤다."}},{"text":{"en":"Exempted suffix and multi-range requests from segmented caching (infra#241, infra#243)","ko":"한 클라이언트가 논리적으로 잘못된 범위를 보내 아침에 오류가 치솟은 뒤, infra#241 을 머지해 끝에서부터의 범위 요청과 여러 범위 요청을 segmented caching 에서 뺐다. 고장 난 병렬 다운로더 두 개가 같은 종류의 오류를 하루에 41,315건 더 만든 뒤 infra#243 도 머지했다."}},{"text":{"en":"Fastly patched the canary configuration bug and removed all PSF traffic from its canary cohort","ko":"Fastly 가 자기 쪽의 카나리 설정 버그를 고쳤고, PyPI 를 포함한 PSF 트래픽 전부를 카나리 집단에서 뺐다."}},{"text":{"en":"Moved the segmented-caching exemption check after URL normalization (infra#245)","ko":"infra#245 를 머지해 segmented caching 예외 검사가 URL 정규화 뒤에 돌도록 순서를 고쳤다. 그 전에는 잘못된 segmented caching 응답이 캐시되어 같은 파일의 뒤 요청에 모두 나갔다."}}],"action_items":[{"text":{"en":"Improve the logging configuration of the file hosting service (infra#238)","ko":"infra#238 을 머지해 파일 호스팅 서비스의 로그 설정을 개선했다."}},{"text":{"en":"Reject HTTP methods that a file host should not receive (infra#239)","ko":"infra#239 를 머지해 파일 호스트에 올 이유가 없는 HTTP 메서드를 거부하게 했다."}},{"text":{"en":"Follow a support ticket with Fastly about segmented-caching range handling, and revert PyPI's own handling code once Fastly fixes it","ko":"segmented caching 의 범위 처리 문제로 Fastly 에 지원 티켓을 열었다. 잘못된 클라이언트 요청에 501 을 내는 것은 틀린 상태 코드 계열이다. Fastly 가 고치면 PyPI 쪽의 처리 코드는 되돌릴 수 있을 것으로 본다."}},{"text":{"en":"Return to Fastly's canary program once clearer controls and notifications exist around that traffic","ko":"이 트래픽을 통제하고 알림을 받는 방법이 더 분명해지면 Fastly 의 카나리 프로그램에 다시 참여한다."}},{"text":{"en":"Hire an infrastructure engineer, partly for PyPI, to catch conditions like this earlier","ko":"PSF 는 지금의 엔지니어 네 명에 더해 인프라 엔지니어 한 명을 뽑는다. 새 엔지니어는 PyPI 도 맡아 이런 상황을 더 일찍 잡고, 일이 난 뒤에 대응하기보다 미리 막을 수 있게 한다."}}],"contributing":["partial-rollout","overlapping-failures","alert-noise"],"recurrence_of":null,"symptoms_text":{"en":"For about two weeks in August 2026, some PyPI users got intermittent 502 and 503 errors when downloading files from files.pythonhosted.org, and installations from PyPI failed. The first two reports of persistent 502s were opened in the support tracker on 17 August.\n\nA report on 18 August reproduced the problem in detail: 88 recorded 502s over six hours across 32 unrelated packages, including the small .whl.metadata range requests installers use to read PEP 658 metadata. A report on 19 August traced the failures to one Fastly cache node, cache-pae2080020, which had returned 502 for every request routed to it for over 19 hours; the x-served-by headers on the failing responses confirmed it.\n\nOn the PyPI side the errors were hard to see. Datadog Logs showed nothing of consequence for the PyPI Files errors at first, and the 5xx baseline was already thousands to tens of thousands of responses, so the increase from 15 August was easy to miss. Fastly's real-time analytics showed B2 errors climbing from 15 August while the S3 archive backend stayed flat at zero, because the fallback was not firing. On 21 August a single client sending logically invalid ranges pushed the count close to a million, and some requests got 501 responses that looked like 502s from outside.","ko":"2026년 8월에 약 2주 동안 일부 PyPI 사용자가 files.pythonhosted.org 에서 파일을 받다가 간헐적으로 502 와 503 을 받았고, PyPI 에서 패키지를 설치하는 일이 실패했다. 사용자들이 지원 트래커에 보고를 올렸다.\n\n8월 17일에 files.pythonhosted.org 에서 502 가 계속 난다는 첫 보고 두 건이 열렸다. 8월 18일의 보고는 6시간 동안 서로 관계없는 패키지 32개에서 502 를 88번 기록했고, 설치 도구가 PEP 658 메타데이터를 읽으려고 보내는 작은 .whl.metadata 범위 요청도 그 안에 있었다.\n\nPyPI 인프라 엔지니어가 Datadog Logs 에서 이 보고에 맞는 PyPI Files 오류를 뒤졌지만 의미 있는 것은 나오지 않았다. 장애 전부터 5xx 가 수천에서 수만 건씩 나는 배경 소음이 있어서, 8월 15일부터 늘어난 양은 알아채기 어려웠다. Fastly 의 실시간 분석에서는 8월 15일부터 B2 오류가 늘었지만 S3 백엔드는 0 에 머물렀다. 실패를 S3 로 넘겨야 할 대체 경로가 작동하지 않았기 때문이다.\n\n8월 19일의 보고가 문제를 Fastly 캐시 노드 cache-pae2080020 하나로 좁혔다. 이 노드로 간 요청은 19시간 넘게 모두 502 를 받았고, 실패한 응답의 x-served-by 헤더가 이를 확인해 줬다.\n\nPyPI 자체 Fastly 설정의 버그도 같은 증상을 만들고 있었다. 502 가 늘었고, 몇몇 경우에는 밖에서 502 처럼 보이는 501 이 났다. 8월 21일 아침에는 논리적으로 잘못된 범위를 보내는 클라이언트 하나 때문에 5xx 가 백만 건 가까이 치솟았다. 8월 24일에는 고장 난 병렬 다운로더 두 개가 하루에 같은 종류의 오류를 41,315건 더 만들었다."},"updated_at":"2026-11-14T12:34:15.903520Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0515","org_slug":"python-software-foundation"}