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
- Match result class types to aggregate return types โ
count()โInt,sum(Long)โLong - Always use
.usewithSqlExpression<T>ingroupBy/sortBy - Use composite types for fragment composition โ wrap joined entities in a data class to preserve field access
- Chain filter fragments โ
filterB(filterA(baseJoin()))composes conditions with AND - Test generated SQL โ use
.buildPrettyFor.Dialect()to inspect output