DioxusLabs/dioxus · error

Tried to unwrap a Result that was an error

Error message

Tried to unwrap a Result that was an error

What it means

WritableResultExt::unwrap_mut locks a signal holding a Result and filters the write lock to the Ok variant via WriteLock::filter_map. If the current value is Err, the filter returns None and this expect panics — the reactive equivalent of Result::unwrap, with the same failure mode.

Source

Thrown at packages/signals/src/write.rs:460

        T: 'static,
    {
        WriteLock::filter_map(self.write(), |v: &mut Option<T>| v.as_mut())
    }
}

impl<T, W> WritableOptionExt<T> for W where W: Writable<Target = Option<T>> {}

/// An extension trait for [`Writable<Result<T, E>>`] that provides some convenience methods.
pub trait WritableResultExt<T, E>: Writable<Target = Result<T, E>> {
    /// Unwraps the inner value mutably, panicking if the Result is an error.
    #[track_caller]
    fn unwrap_mut(&mut self) -> WritableRef<'_, Self, T>
    where
        T: 'static,
        E: 'static,
    {
        WriteLock::filter_map(self.write(), |v| v.as_mut().ok())
            .expect("Tried to unwrap a Result that was an error")
    }

    /// Attempts to mutably access the inner value of the Result.
    #[track_caller]
    fn as_mut(&mut self) -> Result<WritableRef<'_, Self, T>, WritableRef<'_, Self, E>>
    where
        T: 'static,
        E: 'static,
    {
        let write = self.write();
        match write.as_ref() {
            Ok(_) => Ok(WriteLock::map(write, |v| {
                v.as_mut()
                    .ok()
                    .expect("Result variant changed between read and write")
            })),
            Err(_) => Err(WriteLock::map(write, |v| {
                v.as_mut()

View on GitHub (pinned to 393d190a80)

Solutions

  1. Handle both variants with .as_mut(), which returns Result<WritableRef<T>, WritableRef<E>>
  2. Check state first: if signal.read().is_err(), render or propagate the error instead of unwrapping
  3. Reset the signal to an Ok/default value before code that requires unwrap_mut
  4. If unwrap semantics are required, store T and the error in separate signals

Example fix

// before
let value = result_signal.unwrap_mut(); // panics when Err
// after
match result_signal.as_mut() {
    Ok(mut ok) => { *ok += 1; }
    Err(mut err) => { tracing::error!("query failed: {err:?}"); }
}
Defensive patterns

Strategy: validation

Validate before calling

if result_signal.read().is_ok() {
    let mut value = result_signal.unwrap_mut(); // safe now
    *value += 1;
} else {
    // surface the error state instead
}

Type guard

fn signal_is_ok<R: Writable<Target = Result<T, E>>, T, E>(sig: &R) -> bool {
    sig.read().is_ok()
}

Prevention

When it happens

Trigger: Calling signal_of_result.unwrap_mut() while the signal currently holds Err(e): a query/async signal storing its last outcome that has failed, or an optimistic update that left an error behind.

Common situations: Modeling async state as Signal<Result<T, E>> and unwrapping during render after a failed request; error state never cleared before code that assumes success.

Related errors


AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16). Data as JSON: /api/errors/441c76d281fc1c97. Report an issue: GitHub.