clockworklabs/SpacetimeDB · error · Exception

e.ToString()

Error message

e.ToString()

What it means

Result<T,E> is the SDK's error-handling type: Ok carries a value, Err carries an error. UnwrapOrThrow returns the Ok payload; on an Err whose error object is non-null it throws a plain Exception whose message is e.ToString() (the error's own string form). An Err with a null error object instead throws InvalidOperationException.

Source

Thrown at crates/bindings-csharp/BSATN.Runtime/Builtins.cs:658

    public TResult Match<TResult>(Func<T, TResult> onOk, Func<E, TResult> onErr) =>
        this switch
        {
            OkR(var v) => onOk(v),
            ErrR(var e) => onErr(e),
            _ => throw new InvalidOperationException("Unknown Result variant."),
        };

    public static Result<T, E> Ok(T value) => new OkR(value);

    public static Result<T, E> Err(E error) => new ErrR(error);

    public T UnwrapOrThrow()
    {
        return this switch
        {
            OkR(var v) => v,
            ErrR(var e) when e is not null => throw new Exception(e.ToString()),
            ErrR(_) => throw new InvalidOperationException(
                "Result failed without an error object."
            ),
            _ => throw new InvalidOperationException("Unknown Result variant."),
        };
    }

    public T UnwrapOr(T defaultValue) =>
        this switch
        {
            OkR(var v) => v,
            _ => defaultValue,
        };

    public T UnwrapOrElse(Func<E, T> f) =>
        this switch
        {
            OkR(var v) => v,

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Check the Result variant before unwrapping, and handle the Err payload explicitly
  2. If a fallback is acceptable, use result.UnwrapOr(defaultValue) which never throws
  3. When you must unwrap, catch the Exception and read its Message — it is the Err value's ToString()
  4. Fix the underlying condition the error object reports (usually a module- or server-side rejection)

Example fix

// before
var value = result.UnwrapOrThrow(); // throws Exception with e.ToString()

// after
var value = result.UnwrapOr(fallback); // no throw; fallback used on Err
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    return result.UnwrapOrThrow();
}
catch (InvalidOperationException)
{
    // Err with a null error object: log and rethrow as a domain error
    throw;
}
catch (Exception ex)
{
    // Message is the Err value's ToString(): log it for diagnosis
    logger.LogError("Result failed: {Message}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: Calling UnwrapOrThrow on a Result produced by a failed operation — a rejected reducer call or client API that returned Err(error) — without first checking the variant.

Common situations: Prototypes or tests unwrapping results that actually contain business errors (validation failure, permission denied, module rejection); assuming success after an async call without inspecting the outcome.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/dbd66d8cf025ba2c. Report an issue: GitHub.