Reference

Common Errors

Troubleshooting guide for common ExoQuery compilation and runtime errors

Type Mismatch Errors

"Argument type mismatch: actual type is 'Int', but 'Long' was expected"

Cause 1: Using SqlExpression<T> where T is expected.

// Wrong
val month = monthOf(date)  // SqlExpression<String>
groupBy(month)             // โŒ Expects String, got SqlExpression<String>

// Fixed
val month = monthOf(date).use  // String
groupBy(month)                 // โœ“

Cause 2: Result data class field type doesn't match aggregate return type.

// Wrong
data class Stats(val cnt: Long)  // โŒ count() returns Int
Stats(count())

// Fixed
data class Stats(val cnt: Int)   // โœ“
Stats(count())

"Cannot infer type for type parameter 'R'"

Cause: Trying to use .use in a context where it's not valid (typically in function return position).

// Wrong
@SqlFragment
fun isPaid(i: Invoice): Boolean = sql.expression { i.status == "paid" }.use  // โŒ

// Fixed: Return SqlExpression, call .use at call site
@SqlFragment
fun isPaid(i: Invoice): SqlExpression<Boolean> = sql.expression { i.status == "paid" }

// Usage
where { isPaid(i).use }  // โœ“

Runtime SQL Errors in Playground/MCP Tool Code

"SQLITE_ERROR: no such function: DATE_TRUNC"

Cause: Using PostgreSQL-specific functions (or some other dialect-specific functions) with SQLite dialect.

Solution: Use free() with dialect-appropriate SQL:

// SQLite
free("strftime('%Y-%m', ${date})").asPure<String>()

// PostgreSQL
free("DATE_TRUNC('month', ${date})").asPure<String>()

Best Practices to Avoid Errors

  1. Match result class types to aggregate return types โ€” count() โ†’ Int, sum(Long) โ†’ Long
  2. Always use .use with SqlExpression<T> in groupBy/sortBy
  3. Use composite types for fragment composition โ€” wrap joined entities in a data class to preserve field access
  4. Chain filter fragments โ€” filterB(filterA(baseJoin())) composes conditions with AND
  5. Test generated SQL โ€” use .buildPrettyFor.Dialect() to inspect output