SeaQL/sea-orm · warning
called `HasOne::unwrap()` on a `Loaded(None)` value
Error message
called `HasOne::unwrap()` on a `Loaded(None)` value
What it means
HasOne<E>::unwrap() was called on a Loaded(None) value: the relation was loaded and the query succeeded, but no related row matched (dangling foreign key or deleted target). unwrap() intentionally panics on an absent related row since 'none found' is a normal result callers should handle with into_option()/take() or explicit matching.
Source
Thrown at src/entity/compound/has_one.rs:78
match self {
Self::Loaded(Some(model)) => Some(*model),
Self::Unloaded | Self::Loaded(None) => None,
}
}
/// Take ownership of the contained Model, if loaded, leaving `Unloaded` in place.
pub fn take(&mut self) -> Option<E::ModelEx> {
std::mem::take(self).into_option()
}
/// # 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 `HasOne::unwrap()` on an `Unloaded` value"),
Self::Loaded(None) => panic!("called `HasOne::unwrap()` on a `Loaded(None)` value"),
}
}
}
impl<E> HasOne<E>
where
E: EntityTrait,
E::ActiveModelEx: From<E::ModelEx>,
{
pub fn into_active_model(self) -> ActiveHasOne<E> {
match self {
Self::Loaded(Some(model)) => ActiveHasOne::set(Some(*model)),
Self::Unloaded | Self::Loaded(None) => ActiveHasOne::NotSet,
}
}
}
impl<E: EntityTrait> From<HasOne<E>> for Option<Box<E::ModelEx>> {View on GitHub (pinned to e29bcd1b41)
Solutions
- Handle the None case: if let Some(p) = loaded relation value
- Create the missing related row before unwrap, e.g. insert the profile
- Use try_unwrap() to handle missing relations gracefully
Example fix
// before
let profile = user.profile.unwrap();
// after
let profile = match user.profile.try_unwrap()? { Some(p) => p, None => create_default_profile(user).await? }; Defensive patterns
Strategy: fallback
Validate before calling
if matches!(user.profile, HasOne::Loaded(None)) { /* create or default */ } Type guard
fn has_profile<E>(h: &HasOne<Option<E>>) -> bool { matches!(h, HasOne::Loaded(Some(_))) } Try / catch
let profile = user.profile.try_unwrap()?.unwrap_or_else(default_profile);
Prevention
- Handle the no-related-row case for optional one-to-one relations
- Create dependent rows (e.g. profile) in the same transaction as the parent
- Avoid unwrap on Option-typed relations
When it happens
Trigger: Calling .unwrap() on a loaded optional has_one whose related row does not exist — user has no profile row yet.
Common situations: One-to-one relations that are optional by schema; the child row was deleted; insert order mistakes where the child row was never created.
Related errors
- called `BelongsTo::unwrap()` on a `Loaded(None)` value
- called `BelongsTo::unwrap()` on an `Unloaded` value
- index out of bounds: the HasMany is Unloaded (index: {index}
- called `HasOne::unwrap()` on an `Unloaded` value
- Cannot unwrap ActiveValue::NotSet
AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10).
Data as JSON: /api/errors/7fe425938f2ef255.
Report an issue: GitHub.