The Fetch API is powerful but has subtle gotchas that trip up even experienced developers. Whether you're getting a silent undefined, a CORS block, a JSON parse error, or simply no data back at all — this guide covers every common failure mode with working code examples.
8 Common Reasons Fetch Isn't Working
1.CORS Error
If your console shows "blocked by CORS policy", the server isn't allowing requests from your origin. This is a server-side fix. See the full CORS error fix guide →
Console error:
Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policyFix (Express server):
const cors = require('cors');
app.use(cors({ origin: 'http://localhost:3000' }));2.fetch is not defined in Node.js
Fetch is only built-in to Node.js 18+. If you're on an older version or running server-side code, you'll hit this.
ReferenceError: fetch is not defined
Fix — option A: upgrade Node.js
# Check your version node --version # needs to be v18+ nvm install 20 && nvm use 20
Fix — option B: install node-fetch
npm install node-fetch
import fetch from 'node-fetch'; // ESM
// or
const fetch = require('node-fetch'); // CJS (v2)3.Not Awaiting the Response
fetch() returns a Promise. Without await, you're working with a Promise object, not the actual response.
Broken:
// Missing await — res is a Promise, not a Response
const res = fetch('https://api.example.com/data');
console.log(res); // Promise { <pending> }Fixed:
async function getData() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
console.log(data); // actual response data
}4.Not Calling .json() on the Response
fetch() resolves to a Response object, not the data itself. You must call .json() — which is also async — to extract the body.
Broken:
const res = await fetch('https://api.example.com/data');
console.log(res); // Response object, not the data!Fixed:
const res = await fetch('https://api.example.com/data');
const data = await res.json(); // parse the body
console.log(data); // { id: 1, name: "..." }5.Sending Body Without Content-Type: application/json
Without the correct Content-Type header, the server won't know to parse your body as JSON and will likely return a 400 or silently ignore the body.
Broken — missing header:
await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name: 'Alice' }),
// no Content-Type header!
});Fixed:
await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' }),
});6.Wrong URL — Relative vs Absolute
Relative URLs work in browsers but not in Node.js. In Node.js, always use absolute URLs. In browsers, ensure your relative path is correct based on the current route.
Broken (in Node.js):
// In Node.js — relative URLs cause TypeError
const res = await fetch('/api/data');Fixed:
const BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
const res = await fetch(`${BASE_URL}/api/data`);7.401 / 403 — Missing or Invalid Auth Token
fetch() doesn't throw on 4xx status codes. Always check res.ok or res.status.
Broken — not checking status:
const res = await fetch('/api/protected');
const data = await res.json(); // silently fails with 401 bodyFixed — with auth header and status check:
const res = await fetch('/api/protected', {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const data = await res.json();8.Mixed Content — HTTP Request from HTTPS Page
If your site is served over HTTPS but you're fetching an HTTP endpoint, browsers block it as "mixed content". The fix is to ensure your API is also served over HTTPS.
Console error:
Mixed Content: The page at 'https://app.com' was loaded over HTTPS, but requested an insecure resource 'http://api.com'Fix:
// Change your API URL from http:// to https://
const res = await fetch('https://api.example.com/data');
// ^^^^^ use HTTPSHow to Properly Send JSON with Fetch
Here is the complete, correct pattern for a JSON POST request with error handling:
async function postData(url, data) {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(data),
});
if (!res.ok) {
const errorBody = await res.text();
throw new Error(`HTTP ${res.status}: ${errorBody}`);
}
return res.json();
}
// Usage
try {
const result = await postData('https://api.example.com/users', {
name: 'Alice',
email: 'alice@example.com',
});
console.log('Created:', result);
} catch (err) {
console.error('Request failed:', err.message);
}How to Add an Authorization Header in Fetch
// Bearer token (JWT / OAuth)
const res = await fetch('https://api.example.com/profile', {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});
// API Key header
const res = await fetch('https://api.example.com/data', {
headers: {
'X-API-Key': apiKey,
},
});
// Basic auth
const credentials = btoa(`${username}:${password}`);
const res = await fetch('https://api.example.com/data', {
headers: {
'Authorization': `Basic ${credentials}`,
},
});Debug your actual API requests
Use our CORS Tester to check what headers your server is actually returning for your origin.
Debug your actual API requests with our CORS TesterFrequently Asked Questions
Why is fetch returning undefined?
Fetch returns undefined when you don't await the call, or when your async function doesn't return the result. Always use const res = await fetch(url) followed by const data = await res.json().
How do I fix 'fetch is not defined' in Node.js?
Upgrade to Node.js 18+ (which ships with native fetch) or install node-fetch via npm and import it at the top of your file.
Why is my fetch not sending the body?
GET requests cannot have a body — use POST. For POST, make sure you set method: 'POST', headers: { "Content-Type": "application/json" }, and body: JSON.stringify(data).
How do I send JSON with fetch?
Use body: JSON.stringify(data) and add the Content-Type: application/json header. Without stringifying, you'll send [object Object].
Why is fetch returning a CORS error?
CORS errors must be fixed on the server side by adding the correct Access-Control-Allow-Origin header. See the full CORS fix guide.