{"record":{"id":"9e535826467bf9ab","repo":"pnpm/pnpm","slug":"unexpected-token-in-property-path","errorCode":"UNEXPECTED_TOKEN_IN_PROPERTY_PATH","errorMessage":"Unexpected token ${JSON.stringify(token.content)} in property path","messagePattern":"Unexpected token (.+?) in property path","errorType":"exception","errorClass":"UnexpectedTokenError","httpStatus":null,"severity":"error","filePath":"pnpm11/object/property-path/src/parse.ts","lineNumber":73,"sourceCode":" *\n * @param propertyPath The string of property path to parse.\n * @returns The parsed path in the form of an array.\n */\nexport function * parsePropertyPath (propertyPath: string): Generator<string | number, void, void> {\n  type Stack =\n    | ExactToken<'.'>\n    | ExactToken<'['>\n    | [ExactToken<'['>, NumericLiteral | StringLiteral]\n  let stack: Stack | undefined\n\n  for (const token of tokenize(propertyPath)) {\n    if (token.type === 'exact' && token.content === '.') {\n      if (!stack) {\n        stack = token\n        continue\n      }\n\n      throw new UnexpectedTokenError(token)\n    }\n\n    if (token.type === 'exact' && token.content === '[') {\n      if (!stack) {\n        stack = token\n        continue\n      }\n\n      throw new UnexpectedTokenError(token)\n    }\n\n    if (token.type === 'exact' && token.content === ']') {\n      if (!Array.isArray(stack)) throw new UnexpectedTokenError(token)\n\n      const [openBracket, literal] = stack\n      assert.equal(openBracket.type, 'exact')\n      assert.equal(openBracket.content, '[')\n      assert(literal.type === 'numeric-literal' || literal.type === 'string-literal')","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/pnpm/pnpm/blob/6261b7f388016d57ca6b90340342411cd1d0d00f/pnpm11/object/property-path/src/parse.ts#L55-L91","documentation":"Thrown by parsePropertyPath() in @pnpm/object.property-path when a '.' separator token arrives while another separator ('.' or '[') is still pending on the parse stack. Property paths alternate segments and separators (a.b[0][\"c\"]), so two consecutive separators are a syntax error. The offending token content is included in the message.","triggerScenarios":"parsePropertyPath() input with a doubled dot ('a..b', '..a'), or a dot directly after an unconsumed open bracket ('a[.foo]' — '[' sets the stack, then '.' sees it non-empty and throws at parse.ts:73).","commonSituations":"Programmatically joining path segments with '.' (['a','b'].join('.') where a segment is empty), typos in dotfiles keys, or hand-built paths from user input like key + '.' + subkey where subkey starts with '.'.","solutions":["Fix the path: remove the duplicated separator ('a..b' -> 'a.b', 'a[.foo]' -> 'a.foo').","If the path is built by joining, filter out empty segments first: segments.filter(s => s !== '').join('.')","If a segment may contain dots or special characters, quote it instead: 'a[\"b.c\"]'.","Validate paths before parsing with a small check such as !/\\.\\.|\\[\\.|^\\./.test(path)."],"exampleFix":"// before\nparsePropertyPath('a..b')\n\n// after\nparsePropertyPath('a.b')\n// or, when joining dynamically\nconst path = ['a', '', 'b'].filter(s => s !== '').join('.')","handlingStrategy":"validation","validationCode":"// Reject a doubled separator before parsing\nfunction hasDoubledSeparator (path: string): boolean {\n  return /\\.\\.|\\.\\[|\\[\\[/.test(path)\n}\nif (!hasDoubledSeparator(input)) {\n  for (const seg of parsePropertyPath(input)) { /* ... */ }\n}","typeGuard":"function isParseIssue (err: unknown): err is PnpmError {\n  return util.types.isNativeError(err) && 'code' in err && (err as PnpmError).code === 'UNEXPECTED_TOKEN_IN_PROPERTY_PATH'\n}","tryCatchPattern":"try {\n  const path = Array.from(parsePropertyPath(userInput))\n} catch (err) {\n  if (util.types.isNativeError(err) && 'code' in err && err.code === 'UNEXPECTED_TOKEN_IN_PROPERTY_PATH') {\n    // surface a field-level error to the user, not a crash\n    throw new Error(`Invalid property path: ${userInput}`)\n  }\n  throw err\n}","preventionTips":["Never join path segments without filtering empty strings.","Keep a single separator style per junction (dot or bracket, not both).","Run a quick /\\.\\./ regex check on untrusted paths before parsing."],"tags":["property-path","parser","syntax-error","pnpm"],"backgroundTag":"path-expression-syntax-error","analyzedSha":"6261b7f388016d57ca6b90340342411cd1d0d00f","analyzedAt":"2026-08-17T18:30:54.750Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}