Vue version
3.5.32 — also reproduces on every 3.5.13 through 3.5.34 (current latest), and on 3.6.0-beta.12. Last working version is 3.5.12.
Link to minimal reproduction
https://play.vuejs.org/#eNp9UctOwzAQ/JXVnttUPE6hrQSoBzgAAm51D1GyLW4T27KdUBT531k7tPRQ9eadmd2ZkXu8NybrWsIcp6600nhw5FszF6rUynmQnhoHM1j2IKscriCMYHheQ1jdCTWdDHu8wQOrTV144gngOEE3Xms7ExivgVTDVYGQ7+jnD85kxUA3bqjRDC0jthKYDvEpZwo179l5kEIIbByxZDQ58T0ZcITecY+13GRbpxW37KNeYKkbI2uyr8ZL7ikwh8RErqhr/f2cMG9bGh3w8ovK3Rl86/YRE/hmyZHtSOCR84XdkB/oxccL7fl9JBtdtTWrL5Dv5HTdxoyD7KFVFcc+0aW0T43R1ku1+XSLvSflDqVi0KgMSS+Qv/rxQvX/uDfZbdoTKmD4BW+dtWY=
Steps to reproduce
Compile the following SFC (the playground link above contains the exact same source):
<script setup>
const items = [{ id: 1 }, { id: 2 }];
</script>
<template>
<template v-for="item in items" :key="item.id" v-memo="[item]">
<span>{{ item.id }}</span>
</template>
</template>
Equivalent programmatic repro (no SFC needed):
const { compileTemplate } = require('@vue/compiler-sfc');
compileTemplate({
id: 'x',
filename: 'x.vue',
source: \`<template v-for=\"item in items\" :key=\"item.id\" v-memo=\"[item]\"><span>{{ item.id }}</span></template>\`,
});
What is expected?
The template compiles successfully, as it does in 3.5.12 and as the existing test compiler: v-memo transform > on template v-for does for a simple-identifier key (:key=\"x\").
What is actually happening?
compileTemplate throws:
TypeError: Cannot read properties of undefined (reading 'trim')
at processExpression (.../@vue/compiler-core/dist/compiler-core.cjs.prod.js:4406:51)
at .../compiler-core.cjs.prod.js:4840:31
at processFor (.../compiler-core.cjs.prod.js:4997:36)
The three conditions required to trigger the crash:
v-for is on a <template> element (not a regular element).
:key is a non-simple-identifier expression (e.g. member expression item.id, call expression getId(item)).
v-memo is present on the same <template>.
Removing any one of the three (move v-memo to a child, use a destructured/simple-identifier key, or drop v-memo) makes the bug disappear.
Affected versions
| Version |
Result |
| 3.5.12 |
OK |
| 3.5.13 → 3.5.34 (current `latest`) |
THROW |
| 3.6.0-beta.12 |
THROW |
System Info
System:
OS: macOS 26.4.1
CPU: (14) arm64 Apple M4 Pro
Memory: 2.81 GB / 48.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.13.0
npm: 11.6.2
pnpm: 10.30.3
Browsers:
Chrome: 148.0.7778.168
npmPackages:
vue: 3.5.32
@vue/compiler-sfc: 3.5.32 (resolved through vue)
@vitejs/plugin-vue: 6.0.6
vite: 8.0.9
Any additional comments?
The regression was introduced by 99009ee (PR #12014, closes #12013). In transformFor (packages/compiler-core/src/transforms/vFor.ts), the key expression is now processed eagerly whenever memo && keyExp && isDirKey:
if (memo && keyExp && isDirKey) {
if (!__BROWSER__) {
keyProp.exp = keyExp = processExpression(
keyExp as SimpleExpressionNode,
context,
)
}
}
For a non-simple-identifier expression like item.id, processExpression returns a CompoundExpression, which has no .content property.
A few lines below, the isTemplate branch processes the same expression a second time:
if (isTemplate) {
if (memo) {
memo.exp = processExpression(memo.exp, context)
}
if (keyProperty && keyProp.type !== NodeTypes.ATTRIBUTE) {
keyProperty.value = processExpression(keyProperty.value, context)
}
}
This second call hits the early guard !node.content.trim() in processExpression, where node.content is now undefined (compound expressions don't carry it), hence the TypeError.
Possible fixes:
- Skip the second
processExpression call for the key inside the isTemplate branch when the eager call already happened (memo && isDirKey).
- Or short-circuit
processExpression when it receives a node that is not a SimpleExpression.
Vue version
3.5.32— also reproduces on every3.5.13through3.5.34(currentlatest), and on3.6.0-beta.12. Last working version is3.5.12.Link to minimal reproduction
https://play.vuejs.org/#eNp9UctOwzAQ/JXVnttUPE6hrQSoBzgAAm51D1GyLW4T27KdUBT531k7tPRQ9eadmd2ZkXu8NybrWsIcp6600nhw5FszF6rUynmQnhoHM1j2IKscriCMYHheQ1jdCTWdDHu8wQOrTV144gngOEE3Xms7ExivgVTDVYGQ7+jnD85kxUA3bqjRDC0jthKYDvEpZwo179l5kEIIbByxZDQ58T0ZcITecY+13GRbpxW37KNeYKkbI2uyr8ZL7ikwh8RErqhr/f2cMG9bGh3w8ovK3Rl86/YRE/hmyZHtSOCR84XdkB/oxccL7fl9JBtdtTWrL5Dv5HTdxoyD7KFVFcc+0aW0T43R1ku1+XSLvSflDqVi0KgMSS+Qv/rxQvX/uDfZbdoTKmD4BW+dtWY=
Steps to reproduce
Compile the following SFC (the playground link above contains the exact same source):
Equivalent programmatic repro (no SFC needed):
What is expected?
The template compiles successfully, as it does in
3.5.12and as the existing testcompiler: v-memo transform > on template v-fordoes for a simple-identifier key (:key=\"x\").What is actually happening?
compileTemplatethrows:The three conditions required to trigger the crash:
v-foris on a<template>element (not a regular element).:keyis a non-simple-identifier expression (e.g. member expressionitem.id, call expressiongetId(item)).v-memois present on the same<template>.Removing any one of the three (move
v-memoto a child, use a destructured/simple-identifier key, or dropv-memo) makes the bug disappear.Affected versions
System Info
Any additional comments?
The regression was introduced by 99009ee (PR #12014, closes #12013). In
transformFor(packages/compiler-core/src/transforms/vFor.ts), the key expression is now processed eagerly whenevermemo && keyExp && isDirKey:For a non-simple-identifier expression like
item.id,processExpressionreturns aCompoundExpression, which has no.contentproperty.A few lines below, the
isTemplatebranch processes the same expression a second time:This second call hits the early guard
!node.content.trim()inprocessExpression, wherenode.contentis nowundefined(compound expressions don't carry it), hence theTypeError.Possible fixes:
processExpressioncall for the key inside theisTemplatebranch when the eager call already happened (memo && isDirKey).processExpressionwhen it receives a node that is not aSimpleExpression.