{"record":{"id":"4f65ccba9a89af22","repo":"pmndrs/react-three-fiber","slug":"r3f-primitives-without-object-are-invalid","errorCode":null,"errorMessage":"R3F: Primitives without 'object' are invalid!","messagePattern":"R3F: Primitives without 'object' are invalid!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/fiber/src/core/reconciler.tsx","lineNumber":184,"sourceCode":"    return Component as any\n  } else {\n    Object.assign(catalogue, objects)\n  }\n}\n\nfunction validateInstance(type: string, props: HostConfig['props']): void {\n  // Get target from catalogue\n  const name = toPascalCase(type)\n  const target = catalogue[name]\n\n  // Validate element target\n  if (type !== 'primitive' && !target)\n    throw new Error(\n      `R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`,\n    )\n\n  // Validate primitives\n  if (type === 'primitive' && !props.object) throw new Error(`R3F: Primitives without 'object' are invalid!`)\n\n  // Throw if an object or literal was passed for args\n  if (props.args !== undefined && !Array.isArray(props.args)) throw new Error('R3F: The args prop must be an array!')\n}\n\nfunction createInstance(type: string, props: HostConfig['props'], root: RootStore): HostConfig['instance'] {\n  // Remove three* prefix from elements if native element not present\n  type = toPascalCase(type) in catalogue ? type : type.replace(PREFIX_REGEX, '')\n\n  validateInstance(type, props)\n\n  // Regenerate the R3F instance for primitives to simulate a new object\n  if (type === 'primitive' && props.object?.__r3f) delete props.object.__r3f\n\n  return prepare(props.object, root, type, props)\n}\n\nfunction hideInstance(instance: HostConfig['instance']): void {","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/pmndrs/react-three-fiber/blob/ff3899dbf43d2a88895fecf53c147192abfd7431/packages/fiber/src/core/reconciler.tsx#L166-L202","documentation":"In R3F, <primitive> is a special element type that wraps an existing, already-constructed THREE.Object3D (or similar) instead of instantiating a class from the catalogue. Because there is nothing to construct, the object prop is mandatory, and the reconciler's validateInstance throws this error during createInstance/commitUpdate if it is missing. The check prevents primitive from silently rendering an empty/invalid node.","triggerScenarios":"Rendering <primitive /> with no object prop; passing object={undefined} or object={null} (e.g. an object that is still loading, or a memoized value that hasn't been created yet); spreading props where the object key is absent or misspelled (<primitive obj={...} />).","commonSituations":"Rendering a lazily created or async-loaded object before it exists (object={maybeObject} where maybeObject is undefined initially); refactoring from useLoader where the loaded asset can be undefined on first render; a typo'd prop name (obj vs object); HMR losing the memoized object reference.","solutions":["Ensure the object prop is always provided: <primitive object={myObject3D} />.","If the object may be undefined initially (async load), gate rendering: {obj && <primitive object={obj} />} or suspend behind Suspense via useLoader so the object exists when the subtree renders.","Check for prop typos — the prop must be named exactly 'object'.","If the object can be recreated, pass key={obj.uuid} (or key={obj.id}) so React remounts the primitive when the underlying object identity changes, since primitive props are applied as diff, not constructor args."],"exampleFix":"// before\n{data && data.nodes && <primitive object={data.nodes[10]} />}\n<primitive object={obj.model} /> // obj.model is undefined while loading\n\n// after\n{obj.model && <primitive object={obj.model} key={obj.model.uuid} />}\n// or suspend until loaded:\nconst { nodes } = useLoader(GLTFLoader, '/model.glb')\n<primitive object={nodes.MyMesh} />","handlingStrategy":"validation","validationCode":"const obj: THREE.Object3D | undefined = loadedModel?.scene\nreturn (\n  {obj ? <primitive object={obj} key={obj.uuid} /> : <FallbackPlaceholder />}\n)","typeGuard":"const isObject3D = (v: unknown): v is THREE.Object3D =>\n  !!v && typeof v === 'object' && (v as any).isObject3D === true","tryCatchPattern":"null","preventionTips":["Always conditionally render primitives: {obj && <primitive object={obj} />}.","Use Suspense + useLoader so loaded assets are guaranteed to exist at render time.","Remember the prop name is exactly 'object' — TypeScript JSX types help catch typos."],"tags":["react-three-fiber","primitive","object3d","props"],"backgroundTag":"missing-required-prop","analyzedSha":"ff3899dbf43d2a88895fecf53c147192abfd7431","analyzedAt":"2026-08-28T10:16:38.568Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}