Meituan-Dianping/mpvue · warning
<transition> explicit ${name} duration is not a valid number
Error message
<transition> explicit ${name} duration is not a valid number - got ${JSON.stringify(val)}. What it means
Vue's <transition> component accepts an explicit `duration` prop (number or object of enter/leave durations). In development mode, checkDuration validates each value and warns when a duration is set to something that is not a number, e.g. a string like '300'. Vue does not coerce values, so a non-numeric duration silently breaks transition timing; this warning surfaces the mistake.
Source
Thrown at src/platforms/web/runtime/modules/transition.js:281
if (isValidDuration(explicitLeaveDuration)) {
setTimeout(cb, explicitLeaveDuration)
} else {
whenTransitionEnds(el, type, cb)
}
}
})
}
leave && leave(el, cb)
if (!expectsCSS && !userWantsControl) {
cb()
}
}
}
// only used in dev mode
function checkDuration (val, name, vnode) {
if (typeof val !== 'number') {
warn(
`<transition> explicit ${name} duration is not a valid number - ` +
`got ${JSON.stringify(val)}.`,
vnode.context
)
} else if (isNaN(val)) {
warn(
`<transition> explicit ${name} duration is NaN - ` +
'the duration expression might be incorrect.',
vnode.context
)
}
}
function isValidDuration (val) {
return typeof val === 'number' && !isNaN(val)
}
/**View on GitHub (pinned to 6c5d78ee04)
Solutions
- Bind the value so it stays a number: use :duration="300" instead of duration="300".
- If the value comes from config/props, convert it with Number(val) or parseInt(val, 10) before passing.
- If using an object form, ensure both enter and leave keys are numbers.
- Parse user/URL input to numbers before assigning to duration.
Example fix
// before <transition duration="300">...</transition> // after <transition :duration="300">...</transition>
Defensive patterns
Strategy: validation
Validate before calling
function isValidDuration(d) {
if (typeof d === 'number') return !isNaN(d)
if (d && typeof d === 'object') {
return ['enter', 'leave'].every(k => typeof d[k] === 'number' && !isNaN(d[k]))
}
return false
}
// before render: if (!isValidDuration(this.duration)) this.duration = 300 Type guard
function isFiniteDuration(v) {
return typeof v === 'number' && !Number.isNaN(v)
} Prevention
- Always use the :duration binding, never a plain attribute, when passing numbers.
- Coerce external/string config values with Number() before assigning.
- Keep durations as number literals or typed props (default: number).
When it happens
Trigger: Setting the duration prop on <transition> (or explicit enter/leave hooks calling enter/leave with a duration option) to a value whose typeof is not 'number' — e.g. duration="300" without a binding (passes the string '300'), or duration="{enter: 100, leave: '200'}" via a non-bound attribute.
Common situations: Writing duration="300" as a plain HTML attribute instead of :duration="300"; reading durations from JSON/config where they come back as strings; passing NaN-producing expressions; refactoring from numeric literals to props that hold strings.
Related errors
- <transition> explicit ${name} duration is NaN - the duration
- data functions should return an object: https://vuejs.org/v2
- $props is readonly.
- Avoid mutating an injected value directly since the changes
- Injection "${key}" not found
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/2d1d5c86650e5b2e.
Report an issue: GitHub.