auth0/node-jsonwebtoken · error
Expected "${parameterName}" to be a plain object.
Error message
Expected "${parameterName}" to be a plain object. What it means
jwt.sign() validates its payload and options through a schema-driven validate() function. Both must be plain JavaScript objects (prototype Object, not arrays, strings, Maps, class instances from other realms, or null); otherwise the library throws before doing any signing work.
Source
Thrown at sign.js:44
issuer: { isValid: isString, message: '"issuer" must be a string' },
subject: { isValid: isString, message: '"subject" must be a string' },
jwtid: { isValid: isString, message: '"jwtid" must be a string' },
noTimestamp: { isValid: isBoolean, message: '"noTimestamp" must be a boolean' },
keyid: { isValid: isString, message: '"keyid" must be a string' },
mutatePayload: { isValid: isBoolean, message: '"mutatePayload" must be a boolean' },
allowInsecureKeySizes: { isValid: isBoolean, message: '"allowInsecureKeySizes" must be a boolean'},
allowInvalidAsymmetricKeyTypes: { isValid: isBoolean, message: '"allowInvalidAsymmetricKeyTypes" must be a boolean'}
};
const registered_claims_schema = {
iat: { isValid: isNumber, message: '"iat" should be a number of seconds' },
exp: { isValid: isNumber, message: '"exp" should be a number of seconds' },
nbf: { isValid: isNumber, message: '"nbf" should be a number of seconds' }
};
function validate(schema, allowUnknown, object, parameterName) {
if (!isPlainObject(object)) {
throw new Error('Expected "' + parameterName + '" to be a plain object.');
}
Object.keys(object)
.forEach(function(key) {
const validator = schema[key];
if (!validator) {
if (!allowUnknown) {
throw new Error('"' + key + '" is not allowed in "' + parameterName + '"');
}
return;
}
if (!validator.isValid(object[key])) {
throw new Error(validator.message);
}
});
}
function validateOptions(options) {
return validate(sign_options_schema, false, options, 'options');View on GitHub (pinned to b924272f29)
Solutions
- Pass the payload as a plain object, e.g. JSON.parse(rawJson) instead of the raw string
- Omit the options argument entirely rather than passing null/undefined-wrapped values
- If the payload is a Buffer/string primitive, wrap intentionally or use a plain object ({ data: value })
- Ensure the object isn't constructed in another realm (e.g. vm sandbox) — clone with {...obj}
Example fix
// before
const token = jwt.sign(JSON.stringify(payload), secret, null);
// after
const token = jwt.sign(payload, secret, { expiresIn: '1h' }); Defensive patterns
Strategy: type-guard
Validate before calling
function isPlainObject(v) {
if (v === null || typeof v !== 'object' || Array.isArray(v)) return false;
const proto = Object.getPrototypeOf(v);
return proto === Object.prototype || proto === null;
}
if (!isPlainObject(payload)) throw new TypeError('payload must be a plain object');
if (options !== undefined && !isPlainObject(options)) throw new TypeError('options must be a plain object'); Type guard
function isPlainObject(v) {
return typeof v === 'object' && v !== null && !Array.isArray(v) &&
(Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
} Try / catch
try {
token = jwt.sign(payload, secret, options);
} catch (err) {
if (/to be a plain object/.test(err.message)) {
payload = isPlainObject(payload) ? payload : JSON.parse(String(payload));
options = isPlainObject(options) ? options : {};
token = jwt.sign(payload, secret, options);
} else throw err;
} Prevention
- Parse JSON strings before passing as payload; never pass raw strings
- Never pass null/undefined as the options argument; omit it instead
- Wrap Buffers or primitives inside a plain object claim
- Validate inputs at API boundaries with isPlainObject before signing
When it happens
Trigger: jwt.sign('string-payload', secret), jwt.sign(payload, secret, ['array']), passing a Buffer or null as payload/options, or passing a non-plain object created in another vm/context.
Common situations: Passing JSON strings instead of parsed objects (forgetting JSON.parse); passing undefined/null options; passing an object deserialized via a library that produces non-plain prototypes; sending a Buffer payload expecting binary JWT support.
Related errors
- "iat"/"exp"/"nbf" should be a number of seconds
- Unknown key type "${keyType}".
- "alg" parameter for "${keyType}" key type must be one of: ${
- "alg" parameter "${algorithm}" requires curve "${allowedCurv
- Invalid key for this operation, its RSA-PSS parameters do no
AI-assisted analysis of auth0/node-jsonwebtoken@b924272f29 (2026-09-02).
Data as JSON: /api/errors/11e2ce0cadd98ce6.
Report an issue: GitHub.