SeaQL/sea-orm · warning

Should only have one owner

Error message

Should only have one owner

What it means

In the sea_schema shim's `map_result`, when a query fails with a `DbErr` wrapping a `sqlx` error inside an `Arc`, the code calls `Arc::into_inner(err).expect("Should only have one owner")` to unwrap the sqlx error. `Arc::into_inner` returns `None` if other clones of the Arc exist — the panic asserts the error is uniquely owned at that point.

Source

Thrown at src/database/sea_schema_shim.rs:92

fn map_result(result: Result<Vec<QueryResult>, DbErr>) -> Result<Vec<SqlxRow>, SqlxError> {
    match result {
        Ok(rows) => Ok(rows
            .into_iter()
            .filter_map(|r| match r.row {
                #[cfg(feature = "sqlx-mysql")]
                QueryResultRow::SqlxMySql(r) => Some(SqlxRow::MySql(r)),
                #[cfg(feature = "sqlx-postgres")]
                QueryResultRow::SqlxPostgres(r) => Some(SqlxRow::Postgres(r)),
                #[cfg(feature = "sqlx-sqlite")]
                QueryResultRow::SqlxSqlite(r) => Some(SqlxRow::Sqlite(r)),
                #[allow(unreachable_patterns)]
                _ => None,
            })
            .collect()),
        Err(err) => Err(match err {
            DbErr::Conn(RuntimeErr::SqlxError(err)) => {
                Arc::into_inner(err).expect("Should only have one owner")
            }
            DbErr::Exec(RuntimeErr::SqlxError(err)) => {
                Arc::into_inner(err).expect("Should only have one owner")
            }
            DbErr::Query(RuntimeErr::SqlxError(err)) => {
                Arc::into_inner(err).expect("Should only have one owner")
            }
            _ => SqlxError::AnyDriverError(Box::new(err)),
        }),
    }
}

View on GitHub (pinned to e29bcd1b41)

Solutions

  1. Drop/clone-free other references: ensure the DbErr is moved (not cloned) into the shim mapping path.
  2. Avoid keeping clones of the error while calling sea_schema query helpers; clone the string representation instead.
  3. If it recurs, restructure so each error is consumed once, e.g. map to your own error type at the boundary before passing along.

Example fix

// before
let err_clone = err.clone();
log::error!("{}", err_clone);
schema_discovery::map_result(err); // Arc still shared -> panic
// after
log::error!("{}", err); // log first
schema_discovery::map_result(err); // move uniquely-owned error
Defensive patterns

Strategy: try-catch

Try / catch

// the panic comes from Arc::into_inner inside the library; guard by not cloning the error:
let outcome = discovery.query_all(...).await;
match outcome {
    Ok(rows) => { /* ... */ }
    Err(e) => {
        // consume e exactly once; log via formatted string, never clone the DbErr
        return Err(MyError::from(e));
    }
}

Prevention

When it happens

Trigger: The same `DbErr::Conn/Exec/Query(RuntimeErr::SqlxError(...))` value was cloned before being returned from `query_all`/`query_all_raw`, so the Arc has refcount > 1 when mapped. Multi-threaded code sharing the error also triggers it.

Common situations: Application code storing or cloning the returned DbErr (e.g. logging wrappers, error aggregation) while also passing it into schema-inspection helpers; concurrent tasks sharing one error value.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10). Data as JSON: /api/errors/aa30fba25e51f3ae. Report an issue: GitHub.