pnpm/pnpm · error · UnexpectedTokenError
UNEXPECTED_TOKEN_IN_PROPERTY_PATH
UNEXPECTED_TOKEN_IN_PROPERTY_PATH
Error message
Unexpected token ${JSON.stringify(token.content)} in property path What it means
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.
Source
Thrown at pnpm11/object/property-path/src/parse.ts:73
*
* @param propertyPath The string of property path to parse.
* @returns The parsed path in the form of an array.
*/
export function * parsePropertyPath (propertyPath: string): Generator<string | number, void, void> {
type Stack =
| ExactToken<'.'>
| ExactToken<'['>
| [ExactToken<'['>, NumericLiteral | StringLiteral]
let stack: Stack | undefined
for (const token of tokenize(propertyPath)) {
if (token.type === 'exact' && token.content === '.') {
if (!stack) {
stack = token
continue
}
throw new UnexpectedTokenError(token)
}
if (token.type === 'exact' && token.content === '[') {
if (!stack) {
stack = token
continue
}
throw new UnexpectedTokenError(token)
}
if (token.type === 'exact' && token.content === ']') {
if (!Array.isArray(stack)) throw new UnexpectedTokenError(token)
const [openBracket, literal] = stack
assert.equal(openBracket.type, 'exact')
assert.equal(openBracket.content, '[')
assert(literal.type === 'numeric-literal' || literal.type === 'string-literal')View on GitHub (pinned to 6261b7f388)
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).
Example fix
// before
parsePropertyPath('a..b')
// after
parsePropertyPath('a.b')
// or, when joining dynamically
const path = ['a', '', 'b'].filter(s => s !== '').join('.') Defensive patterns
Strategy: validation
Validate before calling
// Reject a doubled separator before parsing
function hasDoubledSeparator (path: string): boolean {
return /\.\.|\.\[|\[\[/.test(path)
}
if (!hasDoubledSeparator(input)) {
for (const seg of parsePropertyPath(input)) { /* ... */ }
} Type guard
function isParseIssue (err: unknown): err is PnpmError {
return util.types.isNativeError(err) && 'code' in err && (err as PnpmError).code === 'UNEXPECTED_TOKEN_IN_PROPERTY_PATH'
} Try / catch
try {
const path = Array.from(parsePropertyPath(userInput))
} catch (err) {
if (util.types.isNativeError(err) && 'code' in err && err.code === 'UNEXPECTED_TOKEN_IN_PROPERTY_PATH') {
// surface a field-level error to the user, not a crash
throw new Error(`Invalid property path: ${userInput}`)
}
throw err
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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 '.'.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- UNEXPECTED_IDENTIFIER_IN_PROPERTY_PATH
- UNEXPECTED_LITERAL_IN_PROPERTY_PATH
- UNEXPECTED_END_OF_PROPERTY_PATH
- UNSUPPORTED_NUMERIC_LITERAL_SUFFIX
- UNSUPPORTED_STRING_LITERAL_ESCAPE_SEQUENCE
AI-assisted analysis of pnpm/pnpm@6261b7f388 (2026-08-17).
Data as JSON: /api/errors/9e535826467bf9ab.
Report an issue: GitHub.