tracel-ai/burn · error
Should have at least one optimizer
Error message
Should have at least one optimizer
What it means
`grad_clipping()` on a module-level optimizer expects the internal `optimizers` vector to be non-empty and calls `.first().expect("Should have at least one optimizer")`. If the `ModuleOptimizer` was constructed without any per-parameter-group optimizers registered, the unwrap panics instead of returning an Option. This is an internal invariant check: a module optimizer with zero optimizers is a construction bug, not a runtime condition.
Source
Thrown at crates/burn-optim/src/optim/module/module_optimizer.rs:92
grad_clipping: None,
}],
}
}
}
impl ModuleOptimizer {
/// Check if the optimizer has gradient clipping.
/// If there are multiple optimizers, checks if any group has gradient clipping.
pub fn has_gradient_clipping(&self) -> bool {
self.optimizers.iter().any(|g| g.grad_clipping.is_some())
}
/// Access the gradient clipping.
/// If there are multiple optimizers, returns the first optimizer's [GradientClipping].
pub fn grad_clipping(&self) -> Option<&GradientClipping> {
self.optimizers
.first()
.expect("Should have at least one optimizer")
.grad_clipping
.as_ref()
}
/// Sets the gradient clipping.
/// If there are multiple optimizers, assigns it to the first one.
///
/// # Arguments
///
/// * `gradient_clipping` - The gradient clipping.
///
/// # Returns
///
/// The optimizer.
pub fn with_grad_clipping(mut self, gradient_clipping: GradientClipping) -> Self {
self.optimizers
.first_mut()
.expect("Should have at least one optimizer")View on GitHub (pinned to d16f7ba2ed)
Solutions
- Ensure the `ModuleOptimizer` is built through its normal constructor/init path so every parameter group registers an optimizer before `grad_clipping()` is called.
- If building manually, guarantee at least one entry is pushed into `optimizers` before use.
- Check that the optimizer record/state you loaded actually contains parameter groups (see `to_record`/`load_record`).
- Replace direct construction with `OptimizerAdapter::from_optimizer` style APIs that derive groups from the model.
Example fix
// before
let opt: ModuleOptimizer<MyOpt> = ModuleOptimizer { optimizers: vec![] };
opt.grad_clipping(); // panics
// after
let opt = OptimizerAdapter::from_optimizer(my_opt, config); // registers groups
opt.grad_clipping(); // Ok(None) or Some(&clip) Defensive patterns
Strategy: validation
Validate before calling
fn has_optimizers<M>(opt: &ModuleOptimizer<M>) -> bool { !opt.is_empty() } // or check group count via to_record()
assert!(has_optimizers(&opt), "optimizer has no parameter groups"); Prevention
- Always create ModuleOptimizer through its official constructor/init path, never with an empty optimizers vec
- Call with_grad_clipping/grad_clipping only after optimizer init with the model
- Verify loaded records produce non-empty groups before use
When it happens
Trigger: Calling `grad_clipping()` on a `ModuleOptimizer` whose `optimizers` vec is empty — i.e. the optimizer was created via a path that never registered any parameter-group optimizers (e.g. a default/degenerate `OptimizerAdapter` built without groups, or a record-loading path that left the vec empty).
Common situations: Constructing a `ModuleOptimizer` manually with an empty optimizer list; deserializing/loading an optimizer state that produced no groups; version or config changes that removed all parameter groups before the clipping accessor is queried (e.g. from a learning-rate/clip scheduler reading grad clipping each step).
Related errors
- capture tensor operations must run inside CaptureDevice::cap
- Tensor is on the wrong backend (expected {backend}).
- Autodiff float tensor is on the wrong backend (expected {bac
- Expected autodiff-wrapped float tensor for backend {backend}
- Distributed operations are not supported for device {other:?
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/2733819389ac1a6c.
Report an issue: GitHub.