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

  1. Bind the value so it stays a number: use :duration="300" instead of duration="300".
  2. If the value comes from config/props, convert it with Number(val) or parseInt(val, 10) before passing.
  3. If using an object form, ensure both enter and leave keys are numbers.
  4. 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

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


AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02). Data as JSON: /api/errors/2d1d5c86650e5b2e. Report an issue: GitHub.