promise returned in function argument where a void return was expected
Promise returned in function argument where a void return was expected (Quick Scoop)
This error is a TypeScript / static‑analysis warning that appears when an **async** or Promise‑returning function is passed somewhere that expects a normal function returning `void` (i.e., nothing).What the error message really means
“Promise returned in function argument where a void return was expected”
In plain terms:
- You passed a callback like
async () => { ... }or a function that returns aPromise<...> - But the API you’re calling expects a function that returns
void(synchronous, no Promise).
- That means your Promise will never be awaited, and any rejection can become an unhandled promise rejection.
Typical places this shows up:
- Event handlers (
process.on, browser events, Node events).
- React / JSX props that expect non‑async callbacks.
- Libraries whose type signature is like
() => voidbut you give themasync () => {}.
Concrete examples (and fixes)
Example 1 – Node process.on
Problematic code:
ts
process.on("uncaughtException", async (error: Error) => {
await this.errorHandler(error);
});
process.onexpects the listener to returnvoid, notPromise<void>.
- Because it never awaits the async function, any thrown error can become an unhandled rejection.
Two common fixes:
- Wrap async logic in a non‑async handler
ts
process.on("uncaughtException", (error: Error) => {
this.errorHandler(error).catch((e) => {
console.error("Error in errorHandler:", e);
});
});
- The listener itself returns
void. - You manually handle the Promise (and errors) inside.
- General pattern using a “middleware” wrapper
ts
function middleware(f: () => Promise<void>) {
f().catch((e) => console.error(e));
}
middleware(async () => {
throw "Error!";
});
- The wrapper is explicitly built to accept a Promise‑returning callback and handle it.
Example 2 – React / event handlers
You may see something like:
tsx
const handleSignIn = async (e: React.SyntheticEvent) => {
e.preventDefault();
// await something...
};
<form onSubmit={handleSignIn}>...</form>
- Depending on the library or lint rule,
onSubmitmight be typed as expecting(event) => void.
- An
asynchandler returnsPromise<void>, triggering the error or rule violation.
Common fixes:
- Inline wrapper that ignores the Promise
tsx
<form
onSubmit={(e) => {
e.preventDefault();
void handleSignIn(e); // "void" makes it explicit we ignore the Promise
}}
>
...
</form>
- Or explicitly type the handler as returning void and handle the Promise inside
tsx
const handleSignIn = (e: React.SyntheticEvent): void => {
e.preventDefault();
void (async () => {
// your async logic here
})();
};
- The outer function returns
void; async work is done in an inner IIFE.
Example 3 – Sonar / S6544 rule
Static analyzers like SonarQube have rules such as S6544, which say things like:
- “Promise returning function provided to attribute where a void return was expected.”
- These rules aim to catch forgotten
awaits and ambiguous Promise usage.
Typical pattern they dislike:
ts
someArray.forEach(async (item) => {
await doSomething(item);
});
forEachexpects a callback returningvoid.- The
asynccallback returnsPromise<void>that is never awaited.
Better alternatives:
ts
// If you want to run them in parallel
await Promise.all(someArray.map(item => doSomething(item)));
// If you want sequential processing
for (const item of someArray) {
await doSomething(item);
}
- Here you control the Promise explicitly, not hidden inside a
voidcallback.
Why this rule exists (the deeper reason)
Static analyzers and TypeScript are trying to protect you from two subtle but nasty problems:
- Silent failure : A Promise rejects inside a callback that nobody awaits or catches → unhandled rejection, sometimes process crash.
- Type confusion : Code assumes “this callback finishes before we move on,” but an async callback might still be running.
By banning Promise‑returning callbacks where void is expected, they force
you to:
- Either handle the Promise yourself (
.then/.catchorawaitat a higher level).
- Or change the API so that it’s allowed to return a Promise (for your own functions).
General strategies to fix “Promise returned where void was expected”
When you see this error, mentally walk through these steps:
- Check the function signature of the API you’re passing the callback into.
- Does it say
() => voidor(...args) => void? Then your callback must not beasync.
- Does it say
- If you control that API:
- Consider changing it from
() => voidto() => void | Promise<void>and, inside it, check whether it returned a Promise.
- Consider changing it from
ts
function process(callback: () => void | Promise<void>) {
const result = callback();
if (result instanceof Promise) {
result.then(() => {
console.log("Asynchronous task completed");
});
}
}
- If you do not control the API:
- Keep the callback synchronous and trigger async work inside:
ts
someApi(() => {
void doAsyncStuff(); // fire-and-forget but explicit
});
* Or ensure any returned Promise is caught/logged at the appropriate layer.
Quick HTML table recap
Here’s an HTML table summarizing common contexts and fixes:
html
<table>
<thead>
<tr>
<th>Context</th>
<th>What’s expected</th>
<th>What you passed</th>
<th>Typical fix</th>
</tr>
</thead>
<tbody>
<tr>
<td>Node <code>process.on</code> listener</td>
<td><code>(err: Error) => void</code> [web:3][web:5]</td>
<td><code>async (err) => Promise<void></code></td>
<td>Use non-async listener and call async function inside with <code>.catch</code>. [web:3][web:5]</td>
</tr>
<tr>
<td>React <code>onSubmit</code>, <code>onClick</code></td>
<td><code>(event) => void</code> [web:2][web:7]</td>
<td><code>async (event) => Promise<void></code></td>
<td>Wrap call: <code>onSubmit={(e) => void handleSubmit(e)}</code>. [web:2][web:7][web:8]</td>
</tr>
<tr>
<td><code>Array.forEach</code> callbacks</td>
<td><code>(item) => void</code> [web:8]</td>
<td><code>async (item) => Promise<void></code></td>
<td>Use <code>for...of</code> with <code>await</code> or <code>Promise.all</code>. [web:8]</td>
</tr>
<tr>
<td>Custom callback-based APIs</td>
<td><code>() => void</code> by default</td>
<td>Async or Promise-returning function</td>
<td>Change type to <code>() => void | Promise<void></code> and handle Promises explicitly. [web:8]</td>
</tr>
</tbody>
</table>
Mini TL;DR
- The error means: “You gave me an async/Promise function where I only accept a normal void callback.”
- Commonly happens with event handlers, React props, and some library callbacks.
- Fix by:
- Keeping the callback itself synchronous and starting async work inside, or
- Changing the API to allow and properly handle a Promise return.
Information gathered from public forums or data available on the internet and portrayed here.