SeaQL/sea-orm · error
called `BelongsTo::unwrap()` on a `Loaded(None)` value
Error message
called `BelongsTo::unwrap()` on a `Loaded(None)` value
What it means
Same optional belongs-to `unwrap` as error 17, but this panic fires when the relation IS loaded yet holds `Loaded(None)` — the foreign key is NULL or no matching parent row exists, so unwrapping an optional parent that is absent fails.
Source
Thrown at sea-orm-sync/src/entity/compound/belongs_to.rs:188
}
}
/// Convert into an `Option<ModelEx>`
pub fn into_option(self) -> Option<E::ModelEx> {
match self {
Self::Loaded(Some(model)) => Some(*model),
Self::Unloaded | Self::Loaded(None) => None,
}
}
/// # Panics
///
/// Panics if called on an `Unloaded` or `Loaded(None)` value.
pub fn unwrap(self) -> E::ModelEx {
match self {
Self::Loaded(Some(model)) => *model,
Self::Unloaded => panic!("called `BelongsTo::unwrap()` on an `Unloaded` value"),
Self::Loaded(None) => panic!("called `BelongsTo::unwrap()` on a `Loaded(None)` value"),
}
}
}
impl<E> BelongsTo<E>
where
E: EntityTrait,
E::ActiveModelEx: From<E::ModelEx>,
{
pub fn into_active_model(self) -> ActiveBelongsTo<E> {
match self {
Self::Loaded(model) => ActiveBelongsTo::set(*model),
Self::Unloaded => ActiveBelongsTo::NotSet,
}
}
}
impl<E> BelongsTo<Option<E>>View on GitHub (pinned to e29bcd1b41)
Solutions
- Handle the None case: match `BelongsTo::Loaded(Some(p))` and treat absent parents explicitly.
- If the relation should always exist, make the foreign key NOT NULL at the schema level and fix orphaned data.
- Use `unwrap_or_default`/return an `Option` to the caller instead of panicking.
- Add a cascade delete or cleanup job to prevent orphan rows.
Example fix
// before
let parent = comment.post.unwrap(); // panics on Loaded(None)
// after
let parent = match comment.post {
BelongsTo::Loaded(Some(p)) => Some(p),
_ => None, // nullable FK: parent may legitimately be absent
}; Defensive patterns
Strategy: fallback
Validate before calling
// Treat Loaded(None) as a legitimate outcome for nullable FKs
let parent = match comment.post {
BelongsTo::Loaded(Some(p)) => Some(p),
_ => None,
}; Type guard
fn has_parent<E>(b: &BelongsTo<Option<E>>) -> bool {
matches!(b, BelongsTo::Loaded(Some(_)))
} Try / catch
// Use fallback semantics instead of unwrap let parent = opt_parent(&comment.post).ok_or(MyError::ParentMissing)?;
Prevention
- Never unwrap optional belongs-to relations backed by nullable FKs
- Enforce NOT NULL + cascade deletes when the parent is semantically required
- Clean up orphaned rows referencing deleted parents
When it happens
Trigger: Calling `child.parent.unwrap()` where `parent` was fetched via `.with(parent::Entity)` but the row's foreign key is NULL or points to a missing parent, yielding `Loaded(None)`.
Common situations: Nullable foreign key columns treated as mandatory; orphaned rows after the parent was deleted without cascading; data imported with dangling references.
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 an `Unloaded` 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 a `Loaded(None)` value
AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10).
Data as JSON: /api/errors/85a17961d70af8dd.
Report an issue: GitHub.