{"record":{"id":"942015c705449dee","repo":"Automattic/mongoose","slug":"mongoose-maps-do-not-support-keys-that-start-with","errorCode":null,"errorMessage":"Mongoose maps do not support keys that start with \"$\", got \"${key}\"","messagePattern":"Mongoose maps do not support keys that start with \"\\$\", got \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/types/map.js","lineNumber":358,"sourceCode":"  writable: false,\n  configurable: false,\n  value: true\n});\n\n/**\n * Since maps are stored as objects under the hood, keys must be strings\n * and can't contain any invalid characters\n * @param {string} key\n * @api private\n */\n\nfunction checkValidKey(key) {\n  const keyType = typeof key;\n  if (keyType !== 'string') {\n    throw new TypeError(`Mongoose maps only support string keys, got ${keyType}`);\n  }\n  if (key.startsWith('$')) {\n    throw new Error(`Mongoose maps do not support keys that start with \"$\", got \"${key}\"`);\n  }\n  if (key.includes('.')) {\n    throw new Error(`Mongoose maps do not support keys that contain \".\", got \"${key}\"`);\n  }\n  if (specialProperties.has(key)) {\n    throw new Error(`Mongoose maps do not support reserved key name \"${key}\"`);\n  }\n}\n\nmodule.exports = MongooseMap;\n","sourceCodeStart":340,"sourceCodeEnd":369,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/types/map.js#L340-L369","documentation":"checkValidKey() rejects Map keys starting with '$'. MongoDB reserves $-prefixed field names for operators, so storing such a key inside the object-backed Map would produce unqueryable or rejected documents.","triggerScenarios":"doc.settings.set('$limit', 5); user-controlled input like usernames or tags that begin with '$' used directly as Map keys.","commonSituations":"Storing user-generated identifiers (payment metadata, feature flags) in a Map without sanitization; migrating Redis-style keys that use $ prefixes.","solutions":["Prefix or escape the key: doc.settings.set('x' + key, value) or replace '$' with '_'","Sanitize external keys before they reach the Map: key = key.replace(/^\\$+/, '_')","Reject $-prefixed keys at the API boundary with a 400 response"],"exampleFix":"// before\ndoc.meta.set('$amount', 5);\n// after\ndoc.meta.set('amount', 5); // or sanitize: key.replace(/^\\$/, '_$')","handlingStrategy":"validation","validationCode":"function sanitizeMapKey(key) {\n  const k = String(key);\n  if (k.startsWith('$')) return '_' + k;\n  return k;\n}\ndoc.settings.set(sanitizeMapKey(userKey), value);","typeGuard":"function isSafeMapKey(key) { const k = String(key); return !k.startsWith('$'); }","tryCatchPattern":"try { doc.settings.set(k, v); } catch (err) { if (/start with \"\\$\"/.test(err.message)) doc.settings.set('_' + k, v); else throw err; }","preventionTips":["Sanitize all user-supplied keys before persisting","Reject $-prefixed keys at API boundaries","Prefer fixed key vocabularies (feature flags) over arbitrary user keys in Maps"],"tags":["mongoose","map","keys","sanitization"],"backgroundTag":"invalid-map-key","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}