linebender/druid · error
TabsPolicy::Build called on a policy that does not support…
Error message
TabsPolicy::Build called on a policy that does not support incremental building
What it means
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.
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
Example fix
// before
let policy = MyTabs::build(my_build_data); // panics for policies without build
// after
let tabs = Tabs::new(MyTabsPolicy::default())
.with_policy(MyTabsPolicy::default())
.on_data(|policy, data| { /* derive tabs from data */ }); Defensive patterns
Strategy: validation
Validate before calling
// Only call build on policies that support it
fn safe_build<P: TabsPolicy>(p: P, b: P::Build) -> Option<P> { None /* default build panics; require an overridden impl */ }
// Prefer: construct the Tabs widget from data instead of calling policy.build Prevention
- 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
When it happens
Trigger: 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`.
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- commands should be dispatched via dispatch_cmd
- command must carry a ContextMenu .
- Expected selector " " but the command was " ".
- {}
- There is no globally active Application
AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10).
Data as JSON: /api/errors/47ff67492a7eba5b.
Report an issue: GitHub.
Appendix: source
Thrown at druid/src/widget/tabs.rs:100
/// Label widget for the tab.
/// Usually implemented with a call to default_make_label ( can't default here because Self::LabelWidget isn't determined)
fn tab_label(
&self,
key: Self::Key,
info: TabInfo<Self::Input>,
data: &Self::Input,
) -> Self::LabelWidget;
/// Change the data to reflect the user requesting to close a tab.
#[allow(unused_variables)]
fn close_tab(&self, key: Self::Key, data: &mut Self::Input) {}
#[allow(unused_variables)]
/// Construct an instance of this TabsFromData from its Build type.
/// The main use case for this is StaticTabs, where the tabs are provided by the app developer up front.
fn build(build: Self::Build) -> Self {
panic!("TabsPolicy::Build called on a policy that does not support incremental building")
}
/// A default implementation for make label, if you do not wish to construct a custom widget.
fn default_make_label(info: TabInfo<Self::Input>) -> Label<Self::Input> {
Label::new(info.name).with_text_color(theme::FOREGROUND_LIGHT)
}
}
/// A TabsPolicy that allows the app developer to provide static tabs up front when building the
/// widget.
#[derive(Clone)]
pub struct StaticTabs<T> {
// This needs be able to avoid cloning the widgets we are given -
// as such it is Rc
tabs: Rc<[InitialTab<T>]>,
}
impl<T> Default for StaticTabs<T> {View on GitHub (pinned to 0f8b1195e4)