Fix: Invalid VNode Type When Creating VNode in Vue.js

Error message:
Invalid vnode type when creating vnode: {type}.
Rendering & VNodes 2025-01-25

What Causes This Warning?

This warning occurs when you pass an invalid type to Vue’s h() or createVNode() functions. Valid types include strings (HTML tags), component objects, and certain special types.

The Problem

import { h } from 'vue'

// ❌ Invalid types
h(null)                    // null is not valid
h(undefined)               // undefined is not valid
h(123)                     // number is not valid
h(true)                    // boolean is not valid
h({})                      // empty object is not a component

The Fix

Use Valid VNode Types

import { h } from 'vue'

// ✅ String (HTML element)
h('div', 'Hello')
h('span', { class: 'text' }, 'Content')

// ✅ Component
import MyComponent from './MyComponent.vue'
h(MyComponent, { prop: 'value' })

// ✅ Fragment
import { Fragment } from 'vue'
h(Fragment, [h('li', 'Item 1'), h('li', 'Item 2')])

// ✅ Teleport
import { Teleport } from 'vue'
h(Teleport, { to: 'body' }, h('div', 'Modal'))

// ✅ Suspense
import { Suspense } from 'vue'
h(Suspense, null, {
  default: () => h(AsyncComponent),
  fallback: () => h('div', 'Loading...')
})

Common Scenarios

Null Component Check

// ❌ Component might be undefined
const MaybeComponent = someCondition ? MyComponent : undefined
h(MaybeComponent) // Error if undefined!

// ✅ Handle null case
const MaybeComponent = someCondition ? MyComponent : null
if (MaybeComponent) {
  return h(MaybeComponent)
}
return h('div', 'Fallback')

// ✅ Or use conditional in render
return someCondition
  ? h(MyComponent)
  : h('div', 'Fallback')

Dynamic Component Resolution

// ❌ Component not found
import { resolveComponent } from 'vue'

const comp = resolveComponent('NonExistentComponent')
h(comp) // Returns undefined if not found!

// ✅ Check before using
const comp = resolveComponent('MyComponent')
if (comp) {
  return h(comp, props)
}
return h('div', 'Component not found')

Async Component Loading

import { defineAsyncComponent, h } from 'vue'

// ✅ Define async component properly
const AsyncComp = defineAsyncComponent(() =>
  import('./HeavyComponent.vue')
)

// Use in render
return h(AsyncComp, { prop: 'value' })

Computed Component Type

import { computed, h } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'

export default {
  props: ['type'],
  setup(props) {
    const component = computed(() => {
      // ❌ Might return undefined
      const map = { a: ComponentA, b: ComponentB }
      return map[props.type]
    })

    return () => {
      // ✅ Check for valid component
      if (!component.value) {
        return h('div', 'Unknown component type')
      }
      return h(component.value)
    }
  }
}

Render Function with Slots

export default {
  setup(props, { slots }) {
    return () => {
      // ❌ Slot might be undefined
      const content = slots.default()

      // ✅ Check slot exists
      return h('div', slots.default?.() || 'No content')
    }
  }
}

List Rendering

import { h } from 'vue'

export default {
  props: ['items'],
  setup(props) {
    return () => {
      return h('ul', props.items.map(item => {
        // ❌ If item.component is invalid
        if (item.component) {
          return h(item.component, { key: item.id })
        }

        // ✅ Provide fallback
        return h('li', { key: item.id }, item.text)
      }))
    }
  }
}

Functional Components

// ✅ Valid functional component
const FunctionalComp = (props, { slots }) => {
  return h('div', { class: props.class }, slots.default?.())
}

// With proper typing
FunctionalComp.props = ['class']

// Usage
h(FunctionalComp, { class: 'wrapper' }, () => 'Content')

Valid Types Summary

TypeExample
Stringh('div'), h('span')
Componenth(MyComponent)
Fragmenth(Fragment, [...])
Teleporth(Teleport, { to })
Suspenseh(Suspense, { ... })
Functionalh((props) => h('div'))
Asynch(defineAsyncComponent(...))

Quick Checklist

  • Verify component imports are correct
  • Check for undefined/null before using h()
  • Use resolveComponent() with fallback handling
  • Use defineAsyncComponent() for async loading
  • Provide fallbacks for conditional components
  • Use Fragment for multiple root elements