---
title: "Async effect callback (next/async-effect)"
description: "React treats an effect's return value as its cleanup; an async callback returns a Promise, so cleanup never runs and errors go unhandled."
url: http://localhost:4173/rules/next/async-effect
updated: 2026-11-11
---

# Async effect callback

> `next/async-effect` is a vetd rule. It flags: Async effect callback. It runs on every `check`, together with the TypeScript check.

| Fact | Value |
| --- | --- |
| Rule id | `next/async-effect` |
| Severity | error |
| Group | React client code |
| Tags | react, correctness |

## Why it matters

React treats an effect's return value as its cleanup; an async callback returns a Promise, so cleanup never runs and errors go unhandled.

## How to fix it

Define an async function inside the effect and call it; return a real cleanup function.

## Credit

Based on work by:

- [React team](https://react.dev): An effect callback must return a cleanup function or nothing; async work belongs in a function called from inside the effect.

## References

- [useEffect – React](https://react.dev/reference/react/useEffect), React
- [Synchronizing with Effects – React](https://react.dev/learn/synchronizing-with-effects), React
- [You Might Not Need an Effect – React](https://react.dev/learn/you-might-not-need-an-effect), React

## Related rules

- [`next/effect-cleanup`](http://localhost:4173/rules/next/effect-cleanup.md)
- [`next/fetch-in-effect`](http://localhost:4173/rules/next/fetch-in-effect.md)

## Get this text from vetd

MCP: call `explain` with `{ "diagnosticId": "next/async-effect" }`. CLI: `npx vetd explain next/async-effect`.

---

[All 92 rules](http://localhost:4173/rules.md) · Previous: [`next/floating-promise`](http://localhost:4173/rules/next/floating-promise.md) · Next: [`next/fetch-in-effect`](http://localhost:4173/rules/next/fetch-in-effect.md)
