{"record":{"id":"47ff67492a7eba5b","repo":"linebender/druid","slug":"tabspolicy-build-called-on-a-policy-that-does-not","errorCode":null,"errorMessage":"TabsPolicy::Build called on a policy that does not support incremental building","messagePattern":"TabsPolicy::Build called on a policy that does not support incremental building","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid/src/widget/tabs.rs","lineNumber":100,"sourceCode":"\n    /// Label widget for the tab.\n    /// Usually implemented with a call to default_make_label ( can't default here because Self::LabelWidget isn't determined)\n    fn tab_label(\n        &self,\n        key: Self::Key,\n        info: TabInfo<Self::Input>,\n        data: &Self::Input,\n    ) -> Self::LabelWidget;\n\n    /// Change the data to reflect the user requesting to close a tab.\n    #[allow(unused_variables)]\n    fn close_tab(&self, key: Self::Key, data: &mut Self::Input) {}\n\n    #[allow(unused_variables)]\n    /// Construct an instance of this TabsFromData from its Build type.\n    /// The main use case for this is StaticTabs, where the tabs are provided by the app developer up front.\n    fn build(build: Self::Build) -> Self {\n        panic!(\"TabsPolicy::Build called on a policy that does not support incremental building\")\n    }\n\n    /// A default implementation for make label, if you do not wish to construct a custom widget.\n    fn default_make_label(info: TabInfo<Self::Input>) -> Label<Self::Input> {\n        Label::new(info.name).with_text_color(theme::FOREGROUND_LIGHT)\n    }\n}\n\n/// A TabsPolicy that allows the app developer to provide static tabs up front when building the\n/// widget.\n#[derive(Clone)]\npub struct StaticTabs<T> {\n    // This needs be able to avoid cloning the widgets we are given -\n    // as such it is Rc\n    tabs: Rc<[InitialTab<T>]>,\n}\n\nimpl<T> Default for StaticTabs<T> {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid/src/widget/tabs.rs#L82-L118","documentation":"In druid's TabsPolicy trait, the default `build` method is a placeholder that panics. Policies that can construct themselves from their Build type (like dynamic tab sources) override it; policies such as StaticTabs do not support incremental building, so calling the default impl aborts. This is an API-misuse guard, not a runtime failure of the tabs widget itself.","triggerScenarios":"Calling `TabsPolicy::build(...)` (or a wrapper that does) on a policy that has not overridden `build` — e.g. invoking `build` on StaticTabs or any custom policy that only implements `tabs`, `tab_info` etc. but relies on the default `build`.","commonSituations":"Writing generic code over `impl TabsPolicy` that assumes every policy can rebuild itself; migrating code after a policy change (swapping a dynamic policy for StaticTabs); calling tabs.build() from a delegate trying to refresh tab contents.","solutions":["Do not call `build` on the policy directly; build the Tabs widget from the full data and let `Tabs::new(policy).on_data(...)` construct tabs from data","Override `fn build(build: Self::Build) -> Self` in your custom TabsPolicy to construct the policy from its Build type","If you need StaticTabs behavior, construct the policy directly (e.g. `StaticTabs` with its tabs field) instead of going through `build`","Route updates through druid's normal data->widget rebuild path instead of manual incremental building"],"exampleFix":"// before\nlet policy = MyTabs::build(my_build_data); // panics for policies without build\n// after\nlet tabs = Tabs::new(MyTabsPolicy::default())\n    .with_policy(MyTabsPolicy::default())\n    .on_data(|policy, data| { /* derive tabs from data */ });","handlingStrategy":"validation","validationCode":"// Only call build on policies that support it\nfn safe_build<P: TabsPolicy>(p: P, b: P::Build) -> Option<P> { None /* default build panics; require an overridden impl */ }\n// Prefer: construct the Tabs widget from data instead of calling policy.build","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call TabsPolicy::build on a concrete policy you did not write","Override build() in any custom TabsPolicy you create","Build tabs from application data via the widget's on_data path"],"tags":["druid","rust","gui","panic","api-misuse"],"backgroundTag":"unsupported-operation","analyzedSha":"0f8b1195e4e073f9597f2865299c3d18f8e4005f","analyzedAt":"2026-09-10T14:27:34.582Z","contentChangedAt":"2026-09-10T14:27:34.582Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}