AJAX - AJAX Error Handling
When you make an AJAX call, several things can go wrong:
-
Network issues (no internet, server unreachable).
-
HTTP errors (404 Not Found, 500 Internal Server Error).
-
Response errors (malformed JSON, unexpected data).
-
Timeouts or aborted requests.
You need to handle these gracefully to avoid breaking your app.
1) Error Types in AJAX
-
Network errors
-
Server unreachable, DNS failure, offline mode.
-
Example:
fetch("http://wrong.url")→ rejected promise.
-
-
HTTP status errors
-
Server responds, but with an error code (
404,401,500, etc.). -
Browser treats it as a valid response → you must check
.okorstatus.
-
-
Response parsing errors
-
Example: calling
.json()on a non-JSON response.
-
-
Timeouts / Aborts
-
Request took too long.
-
Request was manually aborted by
AbortControlleror user action.
-
2) Error Handling with fetch
fetch("/api/data")
.then(response => {
if (!response.ok) { // status not in 200-299
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(data => {
console.log("Data:", data);
})
.catch(error => {
console.error("Fetch error:", error.message);
// Handle: show message to user, retry, fallback, etc.
});
Notes
-
.catch()handles network errors and exceptions in.then(). -
It does not auto-handle HTTP errors — you must check
.ok.
3) Error Handling with XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/data", true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log("Success:", xhr.responseText);
} else {
console.error("HTTP Error:", xhr.status, xhr.statusText);
}
};
xhr.onerror = function() {
console.error("Network error (server unreachable)");
};
xhr.ontimeout = function() {
console.error("Request timed out");
};
xhr.timeout = 5000; // 5 seconds
xhr.send();
4) Handling Timeouts and Aborts
With fetch + AbortController
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000); // 5 sec timeout
fetch("/api/slow", { signal: controller.signal })
.then(res => res.json())
.then(data => console.log("Data:", data))
.catch(err => {
if (err.name === "AbortError") {
console.error("Request aborted (timeout).");
} else {
console.error("Error:", err.message);
}
})
.finally(() => clearTimeout(timeout));
5) Best Practices for Error Handling
-
Check
statuscodes — don’t assume response is success. -
Handle network failures — always use
.catch()oronerror. -
Use timeouts — don’t let requests hang forever.
-
Fallbacks — show cached data, retry with backoff.
-
User-friendly messages — don’t show “500 Internal Server Error” directly. Translate into something clear like “Server temporarily unavailable. Please try again later.”
-
Retry strategy — exponential backoff (retry after 1s, 2s, 4s …).
-
Centralized error handling — wrap your fetch/XHR in a utility function so you don’t duplicate error handling everywhere.
6) Example: Centralized Fetch Wrapper
async function safeFetch(url, options = {}) {
try {
const res = await fetch(url, options);
if (!res.ok) {
return { error: `HTTP ${res.status}: ${res.statusText}` };
}
const data = await res.json().catch(() => null); // safe JSON parsing
return { data };
} catch (err) {
return { error: err.message || "Network error" };
}
}
// Usage
safeFetch("/api/data").then(result => {
if (result.error) {
console.error("Error:", result.error);
} else {
console.log("Data:", result.data);
}
});
Summary
-
Always check
.ok/status. -
Handle network errors with
.catch()oronerror. -
Add timeouts to avoid hanging requests.
-
Give friendly error messages and retry strategies.
-
Use a wrapper to keep code clean.