pmndrs/react-three-fiber · error · Error

`${prefix} ${msg}`

Error message

`${prefix} ${msg}`

What it means

This error is thrown by react-three-test-renderer's expectOne helper when a test query (e.g. tree.getBy / a selector matching instances) does not return exactly one matching instance. The prefix distinguishes the two cases: 'No instances found' means zero nodes matched, 'Expected 1 but found N' means the selector was ambiguous and matched multiple nodes. It exists to make tests deterministic — implicit first-match behavior would hide bugs.

Source

Thrown at packages/test-renderer/src/helpers/testInstance.ts:12

import type { ReactThreeTestInstance } from '../createTestInstance'
import type { Obj } from '../types/internal'

export const expectOne = <TItem>(items: TItem[], msg: string) => {
  if (items.length === 1) {
    return items[0]
  }

  const prefix =
    items.length === 0 ? 'RTTR: No instances found' : `RTTR: Expected 1 but found ${items.length} instances`

  throw new Error(`${prefix} ${msg}`)
}

export const matchProps = (props: Obj, filter: Obj) => {
  for (const key in filter) {
    // Check for matches if filter contains regex matchers
    const isRegex = filter[key] instanceof RegExp
    const shouldMatch = isRegex && typeof props[key] === 'string'
    const match = shouldMatch && filter[key].test(props[key])

    // Bail if props aren't identical and filters found no match
    if (props[key] !== filter[key] && !match) {
      return false
    }
  }

  return true
}

View on GitHub (pinned to ff3899dbf4)

Solutions

  1. Make the selector more specific: add distinguishing props (e.g. tree(mesh, { name: 'target' }) or user props) so exactly one instance matches.
  2. If zero matched, verify the element actually rendered — check for conditional rendering guards, early returns, or Suspense boundaries that suspend the subtree.
  3. If the assertion may run before commit, wrap it in tree.waitFor(...) (or waitFor with a timeout) so the query retries until the node appears.
  4. If you genuinely expect multiple instances, use a query that returns all matches (findAll-style) and assert on the array length instead of expectOne.

Example fix

// before
const instance = expectOne(tree.findAll(mesh), 'mesh') // found 3 <mesh> elements

// after
const instance = expectOne(tree.findAll(mesh).filter(i => i.props.name === 'target'), 'target mesh')
Defensive patterns

Strategy: validation

Validate before calling

// Before calling expectOne, assert the match count yourself
const found = tree.findAll(mesh)
if (found.length === 0) throw new Error('mesh not rendered yet — did the component mount?')
if (found.length > 1) throw new Error(`ambiguous selector: ${found.length} meshes, add a distinguishing prop`)

Type guard

const isSingleMatch = <T>(items: T[]): items is [T] => items.length === 1

Try / catch

try {
  const inst = expectOne(tree.findAll(mesh), 'mesh')
} catch (e) {
  if (e instanceof Error && e.message.startsWith('RTTR:')) {
    // query mismatch: refine selector or wait for render, don't rethrow blindly
  } else throw e
}

Prevention

When it happens

Trigger: Calling expectOne with the result of a findAll-style query inside test-renderer helpers (used by tree('...') selectors / getBy-style APIs) where the JSX rendered 0 matching elements, or where multiple elements share the same type/props (e.g. two <mesh> elements with no distinguishing props).

Common situations: Wrong selector string or PascalCase typo (e.g. 'Mesh' vs 'mesh'), the component under test not actually rendering the expected subtree, assertions running before React has flushed/committed the tree, or queries that are too broad in a scene with repeated objects.

Related errors


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