Getting Started
Install universal-api-errors and normalize your first error — with a decision guide so you don't have to guess.
universal-api-errors turns whatever shape an error arrives in — Axios, fetch, or anything
else — into one predictable, fully-typed UniversalError. No more if (error.response?.status === 401) scattered across every project, copy-pasted into every new one, slightly wrong every
time.
There are five published packages. That's not a typo, and it's not five things you need to install — it's one core, two adapters for the two most common HTTP clients, one integration for the most common data-fetching library on top of them, and one "just give me the common stuff" bundle. Nobody installs all five. Most people install exactly one.
If you'd rather answer two quick questions than read the next section, here you go:
Two questions, one install command. No PhD in package archaeology required.
What sends your API requests?
Meet the family
Here's what's actually in each one — no marketing fog, just what's inside and when you'd reach for it.
@harshilrajput/universal-api-errors-core
The foundation. Everyone else is built on this. Zero runtime dependencies — not even Axios's
types — because it recognizes error shapes by duck-typing instead of importing the libraries
that produce them. Contains parseError(), the UniversalError model, status classification,
validation normalization, retry helpers, and the logger. Install it directly if your HTTP client
isn't Axios or fetch — it still works, via the same duck-typing every adapter is built on.
npm install @harshilrajput/universal-api-errors-core@harshilrajput/universal-api-errors-axios
For when Axios is already sitting in your package.json and isn't going anywhere. Adds
parseAxiosError(), which does the one thing the generic parser can't: reliably tells "the
server responded with an error" apart from "the request never got a response at all." Re-exports
all of core, so this one install is genuinely all you need.
npm install @harshilrajput/universal-api-errors-axios@harshilrajput/universal-api-errors-fetch
Native fetch, zero extra dependencies, mildly smug about it. Adds parseFetchError() —
the one async parser in the whole ecosystem, because reading a Response body is inherently
asynchronous and there's no way around awaiting it once. Also re-exports all of core.
npm install @harshilrajput/universal-api-errors-fetch@harshilrajput/universal-api-errors-react-query
Not a parser — React Query doesn't invent its own error format, so there's nothing new to
parse. What it actually adds: useApiError(), a hook that pulls a normalized error straight
out of a query/mutation result, and createRetry(), which makes React Query's retry option
respect real error classification instead of retrying a 404 the same number of times as a
network blip. Needs react as a peer dependency — this is the one package here that actually
cares whether you're in a browser.
npm install @harshilrajput/universal-api-errors-react-query@harshilrajput/universal-api-errors
The "I don't want to think about it" button. Bundles core + the Axios adapter + the fetch
adapter into a single install. Deliberately does not include React Query — bundling a
React-only hook into a package meant for anyone, including plain Node backends, would force
react into dependency trees that have nothing to do with React. If you use React Query, add it
separately; everything else, this one install covers.
npm install @harshilrajput/universal-api-errorsThe umbrella package combines axios + fetch — not react-query. See why above.
Quick start
import { parseAxiosError } from "@harshilrajput/universal-api-errors-axios";
try {
await axios.get("/api/user");
} catch (err) {
const error = parseAxiosError(err);
error.message; // "Token Expired"
error.status; // 401
error.type; // "Unauthorized"
error.retryable; // false
error.isUnauthorized; // true
}Every adapter re-exports the entire core package, so parseError, UniversalError, retry,
and every helper are all available from the same import — no need to install or import core
separately.
Why this exists
Every project ends up with the same repetitive error-parsing code, because every backend spells its errors differently, and every one of those spellings looked perfectly reasonable to whoever wrote that particular backend:
{ "message": "Invalid Password" }{ "statusCode": 401, "message": "Token Expired", "error": "Unauthorized" }{ "detail": [{ "loc": ["body", "email"], "msg": "field required" }] }parseError() (and the adapters built on top of it) normalize all of these into the same
UniversalError shape, so your error-handling code stops caring where the error came from — and
stops getting rewritten from scratch on every new project.
Next steps
- Axios adapter —
parseAxiosError() - fetch adapter —
parseFetchError() - React Query —
useApiError()andcreateRetry() - Core API reference — everything re-exported by every adapter
- Error types — the full
UniversalErrorshape and its flags - Try it live in the Playground