clockworklabs/SpacetimeDB · error · ArgumentException

Unsupported predicate type '{value.GetType().Name}'. Expecte

Error message

Unsupported predicate type '{value.GetType().Name}'. Expected BoolExpr<{typeof(TRow).Name}> or a boolean column.

What it means

The query builder normalizes every predicate through QueryPredicate.ToBoolExpr, which accepts exactly four shapes: BoolExpr<TRow>, a bool column (Col<TRow,bool> or IxCol<TRow,bool>), and a plain bool. Anything else - an int column, a lambda, a string, or a predicate built for a different table's row type - cannot become a SQL WHERE clause and is rejected with ArgumentException.

Source

Thrown at crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs:97

    public override string ToString() => Sql;

    public static implicit operator BoolExpr<TRow>(bool value) => new(value ? "TRUE" : "FALSE");

    public static implicit operator BoolExpr<TRow>(Col<TRow, bool> col) => col.Eq(true);

    public static implicit operator BoolExpr<TRow>(IxCol<TRow, bool> col) => col.Eq(true);
}

internal static class QueryPredicate
{
    internal static BoolExpr<TRow> ToBoolExpr<TRow>(object value) =>
        value switch
        {
            BoolExpr<TRow> expr => expr,
            Col<TRow, bool> col => col.Eq(true),
            IxCol<TRow, bool> col => col.Eq(true),
            bool b => new BoolExpr<TRow>(b ? "TRUE" : "FALSE"),
            _ => throw new ArgumentException(
                $"Unsupported predicate type '{value.GetType().Name}'. Expected BoolExpr<{typeof(TRow).Name}> or a boolean column.",
                nameof(value)
            ),
        };
}

public readonly struct IxJoinEq<TLeftRow, TRightRow>
{
    internal string LeftRefSql { get; }
    internal string RightRefSql { get; }

    internal IxJoinEq(string leftRefSql, string rightRefSql)
    {
        LeftRefSql = leftRefSql;
        RightRefSql = rightRefSql;
    }
}

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Build explicit boolean expressions with the column operators, e.g. t.Count > 0 or t.Status.Eq("active"), which yield BoolExpr<TRow>
  2. For bool columns, pass the column directly or write t.Flag.Eq(true); both are accepted
  3. Make sure the row type parameter matches the table being queried - do not mix predicates across tables
  4. Replace lambdas with the builder's And/Or/Not composition over columns

Example fix

// before
var q = table.Filter(t => t.Count); // int column, throws 'Unsupported predicate type'

// after
var q = table.Filter(t => t.Count > 0); // BoolExpr<TRow> via operator
Defensive patterns

Strategy: type-guard

Type guard

static bool IsSupportedPredicate<TRow>(object? predicate) =>
    predicate is BoolExpr<TRow> or Col<TRow, bool> or IxCol<TRow, bool> or bool;

Try / catch

try { query = table.Filter(pred); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Unsupported predicate type"))
{ /* rewrite the predicate with column operators before retrying */ }

Prevention

When it happens

Trigger: Passing a raw non-bool column like table.Filter(t => t.Count) where Count is Col<TRow,int>; handing a lambda (boxed as Func<...>) instead of an expression built from column operators; reusing a BoolExpr<OtherRow> built against a different table in this table's query.

Common situations: Porting LINQ-style code and assuming lambdas compile to filters; copy-pasting predicates between queries on different entity types; treating truthiness of numeric columns like C-style languages.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/5380b31455d11e6d. Report an issue: GitHub.