SeaQL/sea-orm · error
called `BelongsTo::unwrap()` on an `Unloaded` value
Error message
called `BelongsTo::unwrap()` on an `Unloaded` value
What it means
`BelongsTo::unwrap` on the non-optional variant returns the loaded parent model but panics when the relation is `Unloaded`, i.e. the belongs-to relation was never fetched. Like `Option::unwrap`, it is intended only after confirming the relation is `Loaded`.
Source
Thrown at sea-orm-sync/src/entity/compound/belongs_to.rs:137
Self::Unloaded => None,
}
}
/// Convert into an `Option<ModelEx>`
pub fn into_option(self) -> Option<E::ModelEx> {
match self {
Self::Loaded(model) => Some(*model),
Self::Unloaded => None,
}
}
/// # Panics
///
/// Panics if called on an `Unloaded` value.
pub fn unwrap(self) -> E::ModelEx {
match self {
Self::Loaded(model) => *model,
Self::Unloaded => panic!("called `BelongsTo::unwrap()` on an `Unloaded` value"),
}
}
}
impl<E> BelongsTo<Option<E>>
where
E: EntityTrait,
{
/// Return true if this optional relation was loaded and no model was found.
pub fn is_not_found(&self) -> bool {
matches!(self, Self::Loaded(None))
}
/// Return true if this optional relation holds no model — i.e. it is either
/// `Unloaded` or was loaded with no match (`is_not_found`).
pub fn is_unloaded_or_not_found(&self) -> bool {
matches!(self, Self::Unloaded | Self::Loaded(None))
}View on GitHub (pinned to e29bcd1b41)
Solutions
- Load the relation before unwrapping: `child::Entity::load().filter_by_id(id).with(parent::Entity).one(db)`.
- Match on `BelongsTo::Loaded(model)` / `Unloaded` and handle the unloaded case instead of panicking.
- Use a fallible accessor (e.g. `try_...` or `as_loaded()`) if available and return an error.
- Ensure the code path that loads parents isn't conditionally skipped.
Example fix
// before let parent = post.author.unwrap(); // panics if unloaded // after let post = post::Entity::load().filter_by_id(id).with(user::Entity).one(db)?.unwrap(); let parent = post.author.unwrap();
Defensive patterns
Strategy: validation
Validate before calling
// Load the relation before unwrapping let post = post::Entity::load().filter_by_id(id).with(user::Entity).one(db)?.unwrap(); assert!(matches!(post.author, BelongsTo::Loaded(_)), "author relation must be loaded");
Type guard
fn loaded_parent<E>(b: &BelongsTo<E>) -> Option<&E::ModelEx> {
match b { BelongsTo::Loaded(m) => Some(m), BelongsTo::Unloaded => None }
} Try / catch
// Avoid panic-catching; check state first
if let Some(parent) = loaded_parent(&post.author) { /* use parent */ } else { /* load it */ } Prevention
- Always call .with(parent::Entity) in loader queries for relations you will read
- Treat relation fields as Unloaded until proven loaded
- In fixtures/tests, load or explicitly set relations before access
When it happens
Trigger: Calling `child.parent.unwrap()` where `parent` is a `BelongsTo` field still in `Unloaded` state — the `with(parent::Entity)` load was skipped, or the model was built/deserialized without loading the relation.
Common situations: Forgetting `.with(...)` in a loader query then accessing the relation; models constructed in tests without loading relations; relation lost after mapping the model to another shape.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- called `BelongsTo::unwrap()` on a `Loaded(None)` value
- index out of bounds: the ActiveHasMany is NotSet (index: {in
- index out of bounds: the HasMany is Unloaded (index: {index}
- index out of bounds: the ActiveHasMany is NotSet (index: {in
- called `BelongsTo::unwrap()` on an `Unloaded` value
AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10).
Data as JSON: /api/errors/2938120f3a5a4669.
Report an issue: GitHub.