Failed to fetch, API 요청 실패 원인 10가지
자바스크립트에서 fetch()로 API를 호출했는데 콘솔에 TypeError: Failed to fetch가 나타날 때가 있습니다. 주소도 맞아 보이고 서버도 실행 중인데 응답조차 확인할 수 없다면 어디부터 점검해야 할지 막막한데요.
Failed to fetch 에러는 API가 단순히 404나 500을 반환했다는 의미와는 다릅니다. 브라우저가 요청을 정상적으로 완료하지 못했거나 응답을 자바스크립트에 전달할 수 없는 상황에서 볼 수 있습니다.
API 요청이 실패하는 대표적인 10가지 이유와 해결 순서를 알아보겠습니다.
Failed to fetch 뜻부터 정확히 이해하기
기본적인 fetch 요청은 다음과 같습니다.
fetch("/api/users")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
여기서 중요한 특징이 하나 있습니다. fetch는 서버가 404 Not Found나 500 Internal Server Error 같은 HTTP 오류 상태를 반환했다고 해서 일반적으로 그 이유만으로 reject되지 않습니다.
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`HTTP 오류: ${response.status}`);
}
const data = await response.json();
따라서 Failed to fetch가 보인다면 상태 코드뿐 아니라 네트워크 연결, CORS, URL, 보안 정책 등을 함께 확인해야 합니다.
Failed to fetch 원인 1, API URL이 잘못된 경우
가장 먼저 요청 주소를 확인하세요. 도메인, 포트, API 경로 중 하나만 틀려도 정상적인 서버에 연결하지 못할 수 있습니다.
fetch("/api/users");
개발 환경에서는 프론트엔드와 백엔드가 서로 다른 포트에서 실행되는 경우도 많습니다. 현재 요청이 실제로 어느 주소로 전송되고 있는지는 브라우저 개발자 도구의 Network 탭에서 확인하는 것이 가장 정확합니다.
환경변수로 API 주소를 관리한다면 값이 비어 있거나 잘못된 서버 주소를 가리키고 있지는 않은지도 살펴보세요.
Failed to fetch 원인 2, CORS 정책 문제
Failed to fetch에서 매우 자주 만나는 원인이 CORS(Cross-Origin Resource Sharing)입니다. 프론트엔드와 API 서버의 출처(origin)가 다르면 브라우저는 서버의 CORS 응답 정책을 확인합니다.
서버가 요청한 출처를 허용하지 않는다면 브라우저 콘솔에 CORS 관련 메시지와 함께 fetch 실패가 나타날 수 있습니다. 이 경우 프론트엔드에서 무작정 옵션을 추가하는 것보다 API 서버가 필요한 Origin, Method, Header를 허용하도록 설정되어 있는지 확인해야 합니다.
콘솔에 blocked by CORS policy 같은 문구가 함께 보인다면 중요한 단서입니다.
Failed to fetch 원인 3, 서버가 실행되지 않은 경우
API 서버 자체가 실행되지 않았다면 브라우저는 연결할 대상이 없으므로 요청을 완료하지 못합니다. 로컬 개발에서는 백엔드 서버를 켜지 않은 채 프론트엔드만 실행하는 실수가 흔합니다.
서버 프로세스가 정상적으로 실행 중인지, 예상한 포트를 사용하고 있는지 확인하세요. 서버가 시작되자마자 다른 오류로 종료된 것은 아닌지도 터미널 로그에서 확인하는 것이 좋습니다.
프론트엔드 콘솔만 보지 말고 백엔드 터미널의 로그도 함께 확인하면 원인을 훨씬 빠르게 좁힐 수 있습니다.
Failed to fetch 원인 4, HTTP와 HTTPS 혼합 문제
HTTPS로 열린 웹페이지에서 보안 수준이 낮은 HTTP 리소스를 요청하면 브라우저의 Mixed Content 정책에 의해 요청이 차단될 수 있습니다.
로컬 개발에서는 잘 동작했는데 HTTPS를 사용하는 실제 배포 환경에서만 Failed to fetch가 발생한다면 API 주소의 프로토콜을 확인해 보세요.
페이지와 API 모두 적절한 HTTPS 구성을 사용하는지 확인하고, 브라우저 콘솔에 Mixed Content 관련 경고가 있는지도 살펴보는 것이 좋습니다.
Failed to fetch 원인 5, OPTIONS preflight 실패
CORS 요청 중에는 실제 API 요청 전에 브라우저가 OPTIONS 방식의 preflight 요청을 먼저 보낼 수 있습니다. 서버가 이 요청을 제대로 처리하지 못하면 실제 POST, PUT, DELETE 등의 요청까지 진행되지 않을 수 있습니다.
특정 HTTP 메서드나 커스텀 헤더, 일부 Content-Type을 사용하는 요청에서는 preflight가 발생할 수 있습니다.
Network 탭에서 실제 API 요청보다 먼저 OPTIONS 요청이 실패하고 있다면 서버의 CORS 설정과 허용 메서드·헤더를 확인하세요.
Failed to fetch 원인 6, 요청 헤더 설정 문제
API에서 요구하는 헤더와 실제 요청이 맞지 않는 경우도 확인해야 합니다.
fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "민수"
})
});
서버가 예상하는 Content-Type과 다른 형식으로 데이터를 전송하거나 인증에 필요한 헤더가 빠져 있다면 요청 처리에 문제가 생길 수 있습니다.
다만 서버가 단순히 401이나 400 같은 HTTP 상태를 반환한 것이라면 그것만으로 fetch가 reject되는 것은 아니라는 점도 구분해야 합니다.
Failed to fetch 원인 7, 인터넷·DNS·네트워크 문제
클라이언트가 서버 자체에 연결할 수 없는 네트워크 문제도 Failed to fetch의 원인이 될 수 있습니다. 인터넷 연결이 끊겼거나 도메인 이름을 해석하지 못하거나 서버에 접근할 수 없는 환경이라면 요청이 정상 완료되지 않습니다.
특정 사용자나 특정 네트워크에서만 문제가 발생한다면 VPN, 프록시, 방화벽 또는 네트워크 정책도 확인 대상이 될 수 있습니다.
같은 API 주소가 브라우저에서 접근 가능한지와 Network 탭에서 요청 자체가 어떻게 실패했는지를 함께 확인하세요.
Failed to fetch 원인 8, SSL/TLS 인증서 문제
HTTPS API의 인증서에 문제가 있다면 브라우저가 보안 연결을 정상적으로 완료하지 못할 수 있습니다. 개발용 서버에서 자체 서명 인증서를 사용하거나 인증서 설정이 잘못된 경우 특히 주의해야 합니다.
배포 직후 갑자기 API 요청이 모두 실패한다면 서버의 HTTPS 설정과 인증서 상태도 점검해 보세요. 단순히 JavaScript 코드만 수정해서 해결할 수 없는 문제일 수 있습니다.
Failed to fetch 원인 9, 브라우저 확장 프로그램이나 보안 정책
일부 요청은 광고 차단 확장 프로그램이나 개인정보 보호 기능, 회사 네트워크의 보안 정책 등에 의해 차단될 수도 있습니다. 특정 브라우저에서만 실패하거나 일부 사용자에게만 문제가 발생한다면 이런 환경 차이도 살펴볼 필요가 있습니다.
개발자 도구에 blocked와 관련된 메시지가 표시되는지 확인하고, 동일한 요청을 다른 정상적인 테스트 환경에서도 비교해 보세요.
다만 보안 기능을 무작정 비활성화하기보다 어떤 정책이 어떤 요청을 차단하는지 먼저 확인하는 것이 중요합니다.
Failed to fetch 원인 10, 요청이 중간에 취소된 경우
AbortController 등을 이용해 fetch 요청을 취소하도록 구현했다면 요청이 완료되기 전에 중단될 수 있습니다.
const controller = new AbortController();
fetch("/api/users", {
signal: controller.signal
});
controller.abort();
페이지 이동이나 컴포넌트 정리 과정에서 요청을 자동 취소하는 코드가 있는 프로젝트라면 의도한 취소인지 확인하세요. 라이브러리를 사용하고 있다면 해당 라이브러리가 요청을 취소하는 조건도 함께 살펴보는 것이 좋습니다.
404·500인데 catch가 실행되지 않는 이유
fetch를 처음 사용할 때 가장 많이 헷갈리는 부분입니다. 서버가 404 또는 500을 반환해도 HTTP 응답 자체를 정상적으로 받았다면 fetch Promise는 resolve될 수 있습니다.
try {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`요청 실패: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
따라서 네트워크 수준의 실패와 HTTP 상태 코드 오류를 별도로 처리하는 습관이 중요합니다. 단순히 catch만 작성하면 404와 500을 놓칠 수 있습니다.
Failed to fetch 해결 체크리스트
| 1단계 | 브라우저 Console의 CORS·보안 메시지 확인 |
| 2단계 | Network 탭에서 실제 요청 URL 확인 |
| 3단계 | API 서버와 포트가 실행 중인지 확인 |
| 4단계 | HTTP·HTTPS 혼합 여부 확인 |
| 5단계 | OPTIONS preflight 요청 확인 |
| 6단계 | Method·Header·Content-Type 확인 |
| 7단계 | 서버의 CORS 설정 확인 |
| 8단계 | 네트워크·DNS·TLS 문제 확인 |
| 9단계 | 확장 프로그램이나 보안 정책 확인 |
| 10단계 | AbortController 등 요청 취소 코드 확인 |
Failed to fetch를 가장 빨리 해결하려면?
Failed to fetch가 나타났다면 JavaScript 코드부터 계속 수정하기보다 브라우저 개발자 도구를 먼저 열어보세요. Console에서 CORS나 Mixed Content 메시지를 확인하고, Network 탭에서는 요청 URL과 OPTIONS 요청, 요청이 실제 서버까지 전달됐는지를 살펴보는 것이 핵심입니다.
또한 404·500과 Failed to fetch를 구분해야 합니다. HTTP 오류 응답을 받았다면 response.ok와 response.status를 확인하고, 요청 자체를 완료하지 못했다면 CORS·네트워크·HTTPS·서버 연결 문제를 우선 점검하세요.
정리하면 URL → 서버 실행 → Network → CORS → HTTPS → OPTIONS → 네트워크 순서로 확인하면 됩니다. Failed to fetch라는 짧은 메시지만 보지 말고 브라우저가 함께 제공하는 단서를 확인하면 API 요청 실패 원인을 훨씬 빠르게 찾을 수 있습니다.