`jwt.sign()` callback is executed twice for "The payload already has an "..." property" errors
Author: pfgithubCreated Sep 10, 2025Updated Mar 30, 2026
Description
The callback to jwt.sign() is executed twice when there is an error Bad "options.issuer" option. The payload already has an "iss" property. I would expect the callback to only be executed once.
Reproduction
// a.mjs
import jwt from "jsonwebtoken";
jwt.sign(
{
iss: "bar",
iat: 1757476476,
},
"secret",
{
algorithm: "HS256",
issuer: "foo",
},
(err, asyncSigned) => {
console.log("callback called:", asyncSigned ?? err?.message);
},
);$> npm init -y && npm add jsonwebtoken
$> node a.mjs
callback called: Bad "options.issuer" option. The payload already has an "iss" property.
callback called: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJiYXIiLCJpYXQiOjE3NTc0NzY0NzZ9.TkSecbZDocHnjwnuDhQRXNvRkxsERNGBkRc6P0wHlNYNotice that "callback called" is printed twice, while I would expect it to be printed only once.
Environment
jsonwebtoken 9.0.2 on Darwin 24.6.0 arm64 arm
Other information
It looks like the error is here:
Typically, return failure() throws which exits the forEach and the function. But when a callback is provided, it only returns from the forEach. The rest of the keys are checked and the rest of the function still runs.
Source: auth0/node-jsonwebtoken