{"record":{"id":"2af7b9ce34981d9a","repo":"Automattic/mongoose","slug":"invalid-path-must-be-either-string-or-array-go","errorCode":null,"errorMessage":"Invalid `path`. Must be either string or array. Got \"${path}\" (type ${typeof path})","messagePattern":"Invalid `path`\\. Must be either string or array\\. Got \"(.+?)\" \\(type (.+?)\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/document.js","lineNumber":1849,"sourceCode":"        obj = value;\n      } else {\n        obj = value;\n      }\n    }\n  }\n};\n\n/**\n * Gets a raw value from a path (no getters)\n *\n * @param {string} path\n * @return {any} Returns the value from the given `path`.\n * @api private\n */\n\nDocument.prototype.$__getValue = function(path) {\n  if (typeof path !== 'string' && !Array.isArray(path)) {\n    throw new TypeError(\n      `Invalid \\`path\\`. Must be either string or array. Got \"${path}\" (type ${typeof path})`\n    );\n  }\n  return utils.getValue(path, this._doc);\n};\n\n/**\n * Increments the numeric value at `path` by the given `val`.\n * When you call `save()` on this document, Mongoose will send a\n * [`$inc`](https://www.mongodb.com/docs/manual/reference/operator/update/inc/)\n * as opposed to a `$set`.\n *\n * #### Example:\n *\n *     const schema = new Schema({ counter: Number });\n *     const Test = db.model('Test', schema);\n *\n *     const doc = await Test.create({ counter: 0 });","sourceCodeStart":1831,"sourceCodeEnd":1867,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/document.js#L1831-L1867","documentation":"TypeError from $__getValue, the internal raw getter used by $inc, populated bookkeeping and plugins: `path` must be a string or an array of keys. Any other type - number, undefined, or a plain object like a MongoDB filter passed by mistake - throws immediately with the received value and its typeof.","triggerScenarios":"Calling doc.$inc(nonString) in a configuration where the schema-type guard is bypassed; plugins or application code calling doc.$__getValue(...) with unvalidated input; path variables that are undefined because of destructuring mistakes.","commonSituations":"Passing a query/filter object where a path string was expected; dynamic code that builds paths and sometimes yields undefined; misuse of internal $-prefixed APIs from copied Stack Overflow snippets.","solutions":["Validate/coerce the path before the call: `if (typeof p !== 'string' && !Array.isArray(p)) return;`","Use the public doc.get(path)/doc.set(path, v) API in application code","Check for null/undefined earlier where the path variable is produced"],"exampleFix":"// before\ndoc.$__getValue(undefined); // TypeError: Invalid `path`\n\n// after\nif (typeof p !== 'string' && !Array.isArray(p)) throw new Error('path must be string or array');\nconst value = doc.$__getValue(p);","handlingStrategy":"type-guard","validationCode":"// Coerce or reject before internal path APIs\nif (typeof path !== 'string' && !Array.isArray(path)) {\n  if (path == null) throw new Error('path is required');\n  path = String(path);\n}\nconst value = doc.$__getValue(path);","typeGuard":"const isValidMongoosePath = (p) => typeof p === 'string' || Array.isArray(p);","tryCatchPattern":"try {\n  const v = doc.$__getValue(p);\n} catch (err) {\n  if (err instanceof TypeError && err.message.includes('Invalid `path`')) {\n    // p was not a string/array; fix the caller that produced it\n  } else { throw err; }\n}","preventionTips":["Prefer public doc.get()/doc.set() over internal $-prefixed APIs","Validate dynamically-built path variables at their source","Do not pass filters, options objects, or numbers where a path is expected"],"tags":["mongoose","internal-api","typeerror","path"],"backgroundTag":"invalid-path-argument","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}