pola-rs/polars · error
NAMED EXPR REGISTRY NOT SET
Error message
NAMED EXPR REGISTRY NOT SET
What it means
Named anonymous aggregations serialize only a name (plus payload); materialization looks up the implementation in a global registry (NAMED_SERDE_REGISTRY_EXPR) that the embedding must install via set_named_serde_registry. When a serialized plan containing such an agg is deserialized in a process where the registry was never set, the Option<Arc<dyn ExprRegistry>> is None and this expect panics.
Source
Thrown at crates/polars-plan/src/dsl/expr/anonymous/agg.rs:37
impl OpaqueStreamingAgg {
pub fn materialize(&self) -> PolarsResult<SpecialEq<Arc<dyn AnonymousAgg>>> {
match self {
Self::Deserialized(t) => Ok(t.clone()),
Self::Named {
name,
payload,
value,
} => feature_gated!("serde", {
use super::named_serde::NAMED_SERDE_REGISTRY_EXPR;
match value {
Some(v) => Ok(v.clone()),
None => Ok(SpecialEq::new(
NAMED_SERDE_REGISTRY_EXPR
.read()
.unwrap()
.as_ref()
.expect("NAMED EXPR REGISTRY NOT SET")
.get_agg(name, payload.as_ref().unwrap())?
.expect("NAMED AGG NOT FOUND"),
)),
}
}),
Self::Bytes(_b) => {
feature_gated!("serde", {
use crate::dsl::anonymous::serde_expr;
serde_expr::deserialize_anon_agg(_b.as_ref()).map(SpecialEq::new)
})
},
}
}
}
impl Hash for OpaqueStreamingAgg {
fn hash<H: Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);View on GitHub (pinned to df599052da)
Solutions
- Call set_named_serde_registry(Arc::new(MyRegistry)) at process startup, before any deserialization
- Ensure every node that will deserialize plans registers an ExprRegistry covering the same names
- If the value variant is cached (value: Some(v)), deserialize is registry-free — prefer sending cached values when possible
- Keep producer and consumer on the same polars version so registry names match
Example fix
// before: deserialize in a fresh process -> panic 'NAMED EXPR REGISTRY NOT SET'
let plan = serde_json::from_str::<LazyFrame>(serialized)?;
// after: install the registry at startup
use polars_plan::dsl::named_serde::{set_named_serde_registry, ExprRegistry};
set_named_serde_registry(std::sync::Arc::new(MyAggRegistry) as _);
let plan = serde_json::from_str::<LazyFrame>(serialized)?; Defensive patterns
Strategy: validation
Validate before calling
// run at process startup, before any deserialization
use polars_plan::dsl::named_serde::{set_named_serde_registry, ExprRegistry};
set_named_serde_registry(std::sync::Arc::new(MyRegistry) as _); Try / catch
let lf = std::panic::catch_unwind(|| bincode::deserialize::<LazyFrame>(bytes))
.map_err(|_| anyhow::anyhow!("plan references unregistered named aggregations"))?; Prevention
- Bootstrap the registry in every process that deserializes plans
- Add a startup self-test that deserializes a sample plan
- Keep producer/consumer polars versions aligned
When it happens
Trigger: Deserializing (serde) a LazyFrame/expression that contains a named anonymous aggregation in a process that did not call polars_plan::dsl::named_serde::set_named_serde_registry first — e.g. sending a serialized plan to a worker node or a fresh subprocess.
Common situations: Distributed/multi-process setups where plans are shipped between processes; custom embeddings that deserialize expressions without bootstrapping the registry; deserializing in a minimal test harness.
Related errors
- NAMED AGG NOT FOUND
- NAMED EXPR REGISTRY NOT SET
- NAMED FUNCTION NOT FOUND
- not implemented
- not implemented
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/1d2203a3ab34b61c.
Report an issue: GitHub.