SeaQL/sea-orm · error
index out of bounds: the HasMany is Unloaded (index: {index}
Error message
index out of bounds: the HasMany is Unloaded (index: {index}) What it means
The `Index<usize>` implementation for `HasMany<E>` (the loaded-model relation wrapper) panics when the relation is `Unloaded` — no child models were fetched — and code indexes into it. Without a loaded collection there is no element to return, so it is reported as out of bounds.
Source
Thrown at sea-orm-sync/src/entity/compound/has_many.rs:102
}
}
impl<E: EntityTrait> From<HasMany<E>> for Option<Vec<E::ModelEx>> {
fn from(value: HasMany<E>) -> Self {
match value {
HasMany::Loaded(models) => Some(models),
HasMany::Unloaded => None,
}
}
}
impl<E: EntityTrait> Index<usize> for HasMany<E> {
type Output = E::ModelEx;
fn index(&self, index: usize) -> &Self::Output {
match self {
HasMany::Unloaded => {
panic!("index out of bounds: the HasMany is Unloaded (index: {index})")
}
HasMany::Loaded(items) => items.index(index),
}
}
}
impl<E: EntityTrait> IntoIterator for HasMany<E> {
type Item = E::ModelEx;
type IntoIter = std::vec::IntoIter<E::ModelEx>;
fn into_iter(self) -> Self::IntoIter {
match self {
HasMany::Loaded(models) => models.into_iter(),
HasMany::Unloaded => Vec::new().into_iter(),
}
}
}
View on GitHub (pinned to e29bcd1b41)
Solutions
- Eager-load the relation: add `.with(children::Entity)` to the loader query before indexing.
- Match on `HasMany::Loaded(items)` vs `Unloaded` and handle the unloaded case.
- Iterate only when loaded, or fall back to a separate query fetching children by foreign key.
- Update the code path that was supposed to populate the relation.
Example fix
// before let user = user::Entity::load().filter_by_id(id).one(db)?.unwrap(); let first = &user.posts[0]; // panics: posts Unloaded // after let user = user::Entity::load().filter_by_id(id).with(post::Entity).one(db)?.unwrap(); let first = user.posts.get(0);
Defensive patterns
Strategy: validation
Validate before calling
// Guard: only index when the HasMany is Loaded
let items = match &user.posts {
HasMany::Loaded(v) => Some(v.as_slice()),
HasMany::Unloaded => None,
}; Type guard
fn as_models<'a, E: EntityTrait>(h: &'a HasMany<E>) -> Option<&'a [E::ModelEx]> {
match h { HasMany::Loaded(v) => Some(v), HasMany::Unloaded => None }
} Try / catch
// Avoid catching the panic; check load state first
if let Some(posts) = as_models(&user.posts) {
if let Some(first) = posts.get(0) { /* use first */ }
} Prevention
- Eager-load with .with(child::Entity) whenever you will access relation collections
- Never assume lazy loading — relations default to Unloaded
- Use .get(index) on the loaded slice to also guard against empty collections
When it happens
Trigger: `parent.children[index]` on a `HasMany` field in `Unloaded` state, i.e. the query did not include `.with(children::Entity)` or the relation was never assigned.
Common situations: Accessing relation collections on models loaded without eager loading; models built in memory (tests, fixtures) where relations were never populated; assuming relations auto-load lazily.
Related errors
- index out of bounds: the ActiveHasMany is NotSet (index: {in
- index out of bounds: the ActiveHasMany is NotSet (index: {in
- called `BelongsTo::unwrap()` on an `Unloaded` value
- called `BelongsTo::unwrap()` on a `Loaded(None)` value
- index out of bounds: the HasMany is Unloaded (index: {index}
AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10).
Data as JSON: /api/errors/9eb53ae9fbc35cc0.
Report an issue: GitHub.