Skip to main content
react

NPM Readmes Should Explain Failure States

Every README explains the happy path. Almost none explain what happens when things go wrong — missing the documentation that actually saves hours of debugging.


4 min read

Every npm README shows you the happy path. Install the package, import the hook, pass in your data, render the result. The examples work. The TypeScript types are present. You copy the snippet and move on. Then something goes wrong in production — a network error, a component that unmounts mid-request, a user who submits an empty form — and the README has nothing to say about it. This is the most common gap in library documentation and the most expensive one to discover at runtime.


What failure states actually matter

Not all failures are equal. The ones that matter for documentation are the ones that are non-obvious and package-specific:

Network or async errors. Does the library re-throw them? Catch and expose them through a callback? Surface them in component state? Log them silently? A hook that returns { data, error, isLoading } is obvious — an error boundary integration that requires a specific error type is not.

Component unmount during async work. A fetch started in useEffect that resolves after the component unmounts. Does the library cancel the request? Suppress the state update? Call setState on an unmounted component and produce a React warning?

Invalid or missing input. What happens if a required prop is undefined? Does the component throw synchronously? Render nothing? Show a fallback? Return an error state? This is almost never documented.

Missing peer dependencies. The peer is listed in package.json but the user forgot to install it. What is the error message? Is it clear, or is it a cryptic Cannot read properties of undefined (reading 'createContext')?

Concurrent renders and strict mode. React 18 strict mode double-invokes effects in development. Does the library handle this? Side effects that run twice in development and once in production produce different behavior, and that behavior should be documented.

The section most READMEs skip

Here is what a failure states section looks like in practice:

## Error handling

**Network errors** are surfaced through the `error` property returned by `useQuery`:

\`\`\`tsx
const { data, error } = useQuery({ queryKey: ['user'], queryFn: fetchUser })
if (error) return <div>Failed to load: {error.message}</div>
\`\`\`

**Unmounted components:** If the component unmounts before the query resolves,
the result is discarded and no state update occurs. No React warning is produced.
The underlying fetch is not cancelled — use an AbortController in your queryFn
if you need network-level cancellation.

**Missing required props:** Passing `undefined` to `queryKey` throws synchronously
with a descriptive error: `"queryKey must be an array"`. This throws during render.
Wrap the component in an error boundary or validate props before rendering.

That section takes 10 minutes to write and is worth more to the integrator than the entire examples section.

Why this is the most useful documentation to write

The happy path is the path you test while developing the library. It works because you built it to work. The failure paths are the ones you may have tested, but the user does not know that. And if you did not test them, documenting them forces you to.

Writing the failure state section of a README is a design review. It surfaces questions: what should happen when the network fails? Should we expose the AbortController or handle it internally? Should invalid input throw or warn? If you cannot answer these questions while writing the documentation, you cannot answer them for the user who hits the problem at 11pm.

The format that works

One subsection per failure category. For each: what triggers it, what the observable behavior is, and what the user should do. Concrete — not "errors are handled gracefully" but "a network error sets error to the thrown value and isLoading to false." Two to four sentences per failure. No prose paragraphs.

The section header can be "Error handling", "Edge cases", or "Failure modes" — the name matters less than its existence. Most users will search for it when something breaks. Make sure it is findable.