pmndrs/react-three-fiber · error · Error

R3F: Cannot set "${prop}". Ensure it is an object before set

Error message

R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".

What it means

applyProps resolves pierced props like 'material-color' by walking from the instance to the final target; if the intermediate root object is missing/not an object (e.g. 'material' is undefined), it cannot traverse and throws 'R3F: Cannot set "prop". Ensure it is an object before setting "key".'

Source

Thrown at packages/fiber/src/core/utils.tsx:428

    if (RESERVED_PROPS.includes(prop)) continue

    // Deal with pointer events, including removing them if undefined
    if (instance && EVENT_REGEX.test(prop)) {
      if (typeof value === 'function') instance.handlers[prop as keyof EventHandlers] = value as any
      else delete instance.handlers[prop as keyof EventHandlers]
      instance.eventCount = Object.keys(instance.handlers).length
      continue
    }

    // Ignore setting undefined props
    // https://github.com/pmndrs/react-three-fiber/issues/274
    if (value === undefined) continue

    let { root, key, target } = resolve(object, prop)

    // Throw an error if we attempted to set a pierced prop to a non-object
    if (target === undefined && (typeof root !== 'object' || root === null)) {
      throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`)
    }

    // Layers must be written to the mask property
    if (target instanceof THREE.Layers && value instanceof THREE.Layers) {
      target.mask = value.mask
    }
    // Set colors if valid color representation for automatic conversion (copy)
    else if (target instanceof THREE.Color && isColorRepresentation(value)) {
      target.set(value)
    }
    // Copy if properties match signatures and implement math interface (likely read-only)
    else if (
      target !== null &&
      typeof target === 'object' &&
      typeof target.set === 'function' &&
      typeof target.copy === 'function' &&
      (value as ClassConstructor | null)?.constructor &&
      (target as ClassConstructor).constructor === (value as ClassConstructor).constructor

View on GitHub (pinned to ff3899dbf4)

Solutions

  1. Ensure the intermediate property exists and is an object before setting pierced props (e.g. give the mesh a default material)
  2. Set the object directly instead of piercing: pass material={new THREE.MeshStandardMaterial()} and then material-color
  3. Check for null intermediates in a wrapper component or use the `flat`/direct prop forms
  4. Guard with a type-check before rendering dynamic prop strings

Example fix

// before
<mesh material-color='red' /> // material is undefined

// after
<mesh material={new THREE.MeshStandardMaterial()} material-color='red' />
Defensive patterns

Strategy: type-guard

Validate before calling

const canPierce = (obj: any, path: string) =>
  path.split('-').slice(0, -1).every((seg) => (obj = obj?.[seg]) != null && typeof obj === 'object')
if (canPierce(mesh, 'material-color')) meshProps['material-color'] = 'red'

Type guard

const hasObjectPath = (object: any, prop: string): boolean => {
  let root: any = object
  for (const seg of prop.split('-').slice(0, -1)) {
    root = root?.[seg]
    if (typeof root !== 'object' || root === null) return false
  }
  return true
}

Try / catch

try {
  applyProps(instance, props)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('R3F: Cannot set')) {
    console.warn(`Skipping invalid pierced prop for ${instance.constructor.name}`)
  } else throw e
}

Prevention

When it happens

Trigger: Setting a pierced prop whose segment is null/undefined, e.g. <mesh material-color='red' /> where material was never assigned, or passing a primitive where an object is expected: position-x on an object whose position is undefined, or shorthand props that resolve to non-object roots.

Common situations: Using attach/pierced syntax on instances created outside R3F, passing props like 'rotation-x' to objects whose rotation is null, upgrading three.js versions where a property became nullable, or constructing custom elements without default object members.


AI-assisted analysis of pmndrs/react-three-fiber@ff3899dbf4 (2026-08-28). Data as JSON: /api/errors/84cbae953738d565. Report an issue: GitHub.