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 a Promise<...>
  • 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 () => void but you give them async () => {}.

Concrete examples (and fixes)

Example 1 – Node process.on

Problematic code:

ts

process.on("uncaughtException", async (error: Error) => {
  await this.errorHandler(error);
});
  • process.on expects the listener to return void, not Promise<void>.
  • Because it never awaits the async function, any thrown error can become an unhandled rejection.

Two common fixes:

  1. 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.
  1. 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, onSubmit might be typed as expecting (event) => void.
  • An async handler returns Promise<void>, triggering the error or rule violation.

Common fixes:

  1. Inline wrapper that ignores the Promise
tsx

<form
  onSubmit={(e) => {
    e.preventDefault();
    void handleSignIn(e); // "void" makes it explicit we ignore the Promise
  }}
>
  ...
</form>
  1. 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);
});
  • forEach expects a callback returning void.
  • The async callback returns Promise<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 void callback.

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/.catch or await at 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:

  1. Check the function signature of the API you’re passing the callback into.
    • Does it say () => void or (...args) => void? Then your callback must not be async.
  1. If you control that API:
    • Consider changing it from () => void to () => void | Promise<void> and, inside it, check whether it returned a Promise.
ts

function process(callback: () => void | Promise<void>) {
  const result = callback();
  if (result instanceof Promise) {
    result.then(() => {
      console.log("Asynchronous task completed");
    });
  }
}
  1. 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) =&gt; void</code> [web:3][web:5]</td>
      <td><code>async (err) =&gt; Promise&lt;void&gt;</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) =&gt; void</code> [web:2][web:7]</td>
      <td><code>async (event) =&gt; Promise&lt;void&gt;</code></td>
      <td>Wrap call: <code>onSubmit={(e) =&gt; void handleSubmit(e)}</code>. [web:2][web:7][web:8]</td>
    </tr>
    <tr>
      <td><code>Array.forEach</code> callbacks</td>
      <td><code>(item) =&gt; void</code> [web:8]</td>
      <td><code>async (item) =&gt; Promise&lt;void&gt;</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>() =&gt; void</code> by default</td>
      <td>Async or Promise-returning function</td>
      <td>Change type to <code>() =&gt; void | Promise&lt;void&gt;</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.