{"record":{"id":"d08709bd744ce0bb","repo":"remotion-dev/remotion","slug":"usetimelinemarqueeselectableitem-must-be-used-inside","errorCode":null,"errorMessage":"useTimelineMarqueeSelectableItem must be used inside TimelineSelectionProvider","messagePattern":"useTimelineMarqueeSelectableItem must be used inside TimelineSelectionProvider","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio/src/components/Timeline/TimelineSelection.tsx","lineNumber":1606,"sourceCode":"\t\t[\n\t\t\tcanSelect,\n\t\t\tgetMarqueeSelection,\n\t\t\tisHighestContext,\n\t\t\tselectedItems,\n\t\t\tselectItems,\n\t\t],\n\t);\n\n\treturn {marqueeRect, onPointerDownCapture};\n};\n\nexport const useTimelineMarqueeSelectableItem = (\n\titem: TimelineSelection | null,\n\tref: React.RefObject<Element | null>,\n) => {\n\tconst selectionContext = useContext(TimelineRowSelectionContext);\n\tif (selectionContext === null) {\n\t\tthrow new Error(\n\t\t\t'useTimelineMarqueeSelectableItem must be used inside TimelineSelectionProvider',\n\t\t);\n\t}\n\n\tconst {registerMarqueeSelectableItem} = selectionContext;\n\n\tuseEffect(() => {\n\t\tif (item === null) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn registerMarqueeSelectableItem(\n\t\t\titem,\n\t\t\t() => ref.current?.getBoundingClientRect() ?? null,\n\t\t);\n\t}, [item, ref, registerMarqueeSelectableItem]);\n};\n","sourceCodeStart":1588,"sourceCodeEnd":1624,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio/src/components/Timeline/TimelineSelection.tsx#L1588-L1624","documentation":"useTimelineMarqueeSelectableItem is an internal Studio hook that registers an element as marquee-selectable in the Timeline. It reads TimelineRowSelectionContext and throws if that context is null, meaning the hook was called outside TimelineSelectionProvider.","triggerScenarios":"Calling useTimelineMarqueeSelectableItem from a custom Studio component rendered outside the Timeline's TimelineSelectionProvider, or a custom Timeline row/item composition that omits the provider.","commonSituations":"Forking or extending Studio's Timeline UI and moving a row component to a different subtree; writing a custom timeline plugin; refactoring that reordered providers so the consumer is no longer a descendant.","solutions":["Wrap the component calling the hook inside <TimelineSelectionProvider> (or move it back under the Timeline's provider subtree).","Check the component's position in the React tree with React DevTools to confirm TimelineRowSelectionContext is provided above it.","If the hook was called from a module-level or event-handler context instead of a component body, move the call into a component/hook render path.","Compare against the upstream TimelineSelection.tsx usage to restore the intended provider nesting."],"exampleFix":"// before\n<CustomRow>{/* hook called inside */}</CustomRow>\n// after\n<TimelineSelectionProvider>\n  <CustomRow>{/* hook called inside */}</CustomRow>\n</TimelineSelectionProvider>","handlingStrategy":"validation","validationCode":"// guard before calling the hook\nconst inProvider = useContext(TimelineRowSelectionContext) !== null; // conceptually\n// only call useTimelineMarqueeSelectableItem when rendering inside TimelineSelectionProvider","typeGuard":null,"tryCatchPattern":"try {\n  registerItem();\n} catch (e) {\n  if (e.message.includes('must be used inside TimelineSelectionProvider')) {\n    console.warn('Component rendered outside TimelineSelectionProvider');\n  } else throw e;\n}","preventionTips":["Keep all selection hooks' consumers as descendants of TimelineSelectionProvider.","When extracting Timeline components, preserve the provider subtree.","Render custom Timeline items inside the provider in tests and Storybook."],"tags":["react","context","hooks","studio"],"backgroundTag":"missing-required-argument","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}