{"record":{"id":"c0e4707ebeedb543","repo":"pmndrs/react-three-fiber","slug":"timed-out-after-timeout-ms","errorCode":null,"errorMessage":"Timed out after ${timeout}ms.","messagePattern":"Timed out after (.+?)ms\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/test-renderer/src/helpers/waitFor.ts","lineNumber":19,"sourceCode":"import { act } from 'react'\n\nexport interface WaitOptions {\n  interval?: number\n  timeout?: number\n}\n\nexport async function waitFor(\n  callback: () => boolean | void,\n  { interval = 50, timeout = 5000 }: WaitOptions = {},\n): Promise<void> {\n  await act(async () => {\n    const start = performance.now()\n\n    while (true) {\n      const result = callback()\n      if (result || result == null) break\n      if (interval) await new Promise((resolve) => setTimeout(resolve, interval))\n      if (timeout && performance.now() - start >= timeout) throw new Error(`Timed out after ${timeout}ms.`)\n    }\n  })\n}\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/pmndrs/react-three-fiber/blob/ff3899dbf43d2a88895fecf53c147192abfd7431/packages/test-renderer/src/helpers/waitFor.ts#L1-L23","documentation":"This error is thrown by react-three-test-renderer's waitFor helper when the provided callback still returns a falsy value after the configured timeout has elapsed. waitFor polls callback() (with an optional interval between checks) until it returns truthy, or null/undefined which is treated as 'stop waiting'. Its purpose is to fail fast on asynchronous rendering that never completes within the test's time budget.","triggerScenarios":"Calling waitFor(() => someCondition, { timeout }) where someCondition stays falsy: e.g. waiting for a mesh that never mounts, a Suspense resource that never resolves, an animation/state update that never happens, or passing a callback whose truthiness check is wrong (returns 0, '', false indefinitely).","commonSituations":"Async data fetching that hangs in tests (unmocked fetch/asset loader), components gated behind a state flag that the test never triggers, timeouts that are too short for a debounced/animated update, or awaiting an event that the renderer never fires because the scene is static.","solutions":["Verify the condition is actually reachable — run the same interaction/assertion synchronously to confirm what state waitFor is polling.","If the awaited update legitimately takes longer (debounce, suspense load, animation frames), increase the timeout (and optionally interval) passed to waitFor.","If a resource never resolves, mock the asset/data load (mock loader, fixture data) so the subtree finishes rendering.","Ensure the callback returns something truthy on success; note that returning null/undefined makes waitFor exit immediately without error, so return an actual boolean/instance."],"exampleFix":"// before\nawait tree.waitFor(() => tree.findAll(specificMesh).length > 0) // hangs -> Timed out after 5000ms.\n\n// after\nawait tree.waitFor(() => tree.findAll(specificMesh).length > 0, { timeout: 10000, interval: 100 })\n// or trigger the state that mounts the mesh before waiting:\nact(() => { setIsReady(true) })","handlingStrategy":"retry","validationCode":"// Make the condition self-evidently satisfiable before waiting\nconst found = tree.findAll(target)\nif (found.length === 0 && !willEverMount(target)) {\n  // skip waitFor — nothing to wait for\n}","typeGuard":"null","tryCatchPattern":"try {\n  await tree.waitFor(() => tree.findAll(target).length > 0, { timeout: 5000, interval: 50 })\n} catch (e) {\n  if (e instanceof Error && /Timed out after/.test(e.message)) {\n    // dump current tree to debug what actually rendered\n    console.log(JSON.stringify(tree.toTree(), null, 2))\n  } else throw e\n}","preventionTips":["Set explicit, generous timeouts for asset-loading tests.","Mock async loaders so waits are deterministic.","Return a real boolean/instance from the callback (null/undefined exits immediately)."],"tags":["react-three-fiber","testing","timeout","async","waitfor"],"backgroundTag":"async-waitfor-timeout","analyzedSha":"ff3899dbf43d2a88895fecf53c147192abfd7431","analyzedAt":"2026-08-28T10:16:38.568Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}