{"record":{"id":"11e2ce0cadd98ce6","repo":"auth0/node-jsonwebtoken","slug":"expected-parametername-to-be-a-plain-object","errorCode":null,"errorMessage":"Expected \"${parameterName}\" to be a plain object.","messagePattern":"Expected \"(.+?)\" to be a plain object\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sign.js","lineNumber":44,"sourceCode":"  issuer: { isValid: isString, message: '\"issuer\" must be a string' },\n  subject: { isValid: isString, message: '\"subject\" must be a string' },\n  jwtid: { isValid: isString, message: '\"jwtid\" must be a string' },\n  noTimestamp: { isValid: isBoolean, message: '\"noTimestamp\" must be a boolean' },\n  keyid: { isValid: isString, message: '\"keyid\" must be a string' },\n  mutatePayload: { isValid: isBoolean, message: '\"mutatePayload\" must be a boolean' },\n  allowInsecureKeySizes: { isValid: isBoolean, message: '\"allowInsecureKeySizes\" must be a boolean'},\n  allowInvalidAsymmetricKeyTypes: { isValid: isBoolean, message: '\"allowInvalidAsymmetricKeyTypes\" must be a boolean'}\n};\n\nconst registered_claims_schema = {\n  iat: { isValid: isNumber, message: '\"iat\" should be a number of seconds' },\n  exp: { isValid: isNumber, message: '\"exp\" should be a number of seconds' },\n  nbf: { isValid: isNumber, message: '\"nbf\" should be a number of seconds' }\n};\n\nfunction validate(schema, allowUnknown, object, parameterName) {\n  if (!isPlainObject(object)) {\n    throw new Error('Expected \"' + parameterName + '\" to be a plain object.');\n  }\n  Object.keys(object)\n    .forEach(function(key) {\n      const validator = schema[key];\n      if (!validator) {\n        if (!allowUnknown) {\n          throw new Error('\"' + key + '\" is not allowed in \"' + parameterName + '\"');\n        }\n        return;\n      }\n      if (!validator.isValid(object[key])) {\n        throw new Error(validator.message);\n      }\n    });\n}\n\nfunction validateOptions(options) {\n  return validate(sign_options_schema, false, options, 'options');","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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}"],"exampleFix":"// before\nconst token = jwt.sign(JSON.stringify(payload), secret, null);\n// after\nconst token = jwt.sign(payload, secret, { expiresIn: '1h' });","handlingStrategy":"type-guard","validationCode":"function isPlainObject(v) {\n  if (v === null || typeof v !== 'object' || Array.isArray(v)) return false;\n  const proto = Object.getPrototypeOf(v);\n  return proto === Object.prototype || proto === null;\n}\nif (!isPlainObject(payload)) throw new TypeError('payload must be a plain object');\nif (options !== undefined && !isPlainObject(options)) throw new TypeError('options must be a plain object');","typeGuard":"function isPlainObject(v) {\n  return typeof v === 'object' && v !== null && !Array.isArray(v) &&\n    (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);\n}","tryCatchPattern":"try {\n  token = jwt.sign(payload, secret, options);\n} catch (err) {\n  if (/to be a plain object/.test(err.message)) {\n    payload = isPlainObject(payload) ? payload : JSON.parse(String(payload));\n    options = isPlainObject(options) ? options : {};\n    token = jwt.sign(payload, secret, options);\n  } else throw err;\n}","preventionTips":["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"],"tags":["jwt","type-error","payload-validation"],"backgroundTag":"jwt-invalid-payload-type","analyzedSha":"b924272f29192e12926b5414546f7c5bfcc9579d","analyzedAt":"2026-09-02T21:29:06.876Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}