Meituan-Dianping/mpvue · warning
<transition> explicit ${name} duration is NaN - the duration
Error message
<transition> explicit ${name} duration is NaN - the duration expression might be incorrect. What it means
This is the NaN branch of checkDuration: the duration prop on <transition> is a number type but evaluates to NaN, which usually means the duration expression is computed incorrectly (e.g. Number('abc'), undefined arithmetic). NaN durations make transition timing impossible, so Vue warns in development.
Source
Thrown at src/platforms/web/runtime/modules/transition.js:287
})
}
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)
}
/**
* Normalize a transition hook's argument length. The hook may be:
* - a merged hook (invoker) with the original in .fns
* - a wrapped component method (check ._length)
* - a plain function (.length)
*/
function getHookArgumentsLength (fn: Function): boolean {View on GitHub (pinned to 6c5d78ee04)
Solutions
- Fix the expression producing the duration so it yields a real number (validate input before Number()/parseFloat).
- Guard against undefined: use :duration="Number(str) || 300" with a sane default.
- If parsing '300ms' style strings, strip units first: parseFloat('300ms').
- Log the value in dev to find where NaN originates.
Example fix
// before <transition :duration="parseFloat(this.durationStr)">...</transition> // after <transition :duration="parseFloat(this.durationStr) || 300">...</transition>
Defensive patterns
Strategy: validation
Validate before calling
function toDuration(v, fallback = 300) {
const n = typeof v === 'string' ? parseFloat(v) : Number(v)
return Number.isFinite(n) ? n : fallback
}
// use: :duration="toDuration(rawDuration)" Type guard
function isRealNumber(v) {
return typeof v === 'number' && Number.isFinite(v)
} Prevention
- Use Number.isFinite() checks on computed durations before applying them.
- Provide default fallbacks with the || operator on parsed values.
- Trace NaN sources: log intermediate expressions when duration is computed.
- Parse unit strings ('300ms') with parseFloat, not Number.
When it happens
Trigger: Passing a computed duration to <transition> (or explicit enter/leave hooks) whose value is a number-typed NaN — e.g. :duration="parseFloat(str)" where str is not numeric, or arithmetic like this.delay * 2 when this.delay is undefined.
Common situations: Parsing strings from attributes or config without validating; uninitialized reactive data used in the expression; a computed that divides by zero or multiplies undefined; unit strings like '300ms' fed to Number().
Related errors
- <transition> explicit ${name} duration is not a valid number
- $props is readonly.
- Avoid mutating an injected value directly since the changes
- Injection "${key}" not found
- Invalid Component definition: ${String(Ctor)}
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/e2ff7f5016fb6eca.
Report an issue: GitHub.