greenrobot/greenDAO · error · DaoException
Unexpected row count:
Error message
Unexpected row count:
What it means
A COUNT(*) aggregate must return exactly one row. count() checks cursor.isLast() after moveToNext(); if more than one row came back, the result set shape is unexpected and DaoException("Unexpected row count: N") is thrown with the actual row count.
Solutions
- Ensure the count query SQL contains no GROUP BY and is a pure aggregate select
- Rebuild via buildCount() rather than reusing a regular Query's SQL
- Inspect the generated SQL and the cursor row count to find why multiple rows are produced
Example fix
// before // custom SQL with GROUP BY passed into a count cursor "SELECT dept, COUNT(*) FROM USER GROUP BY dept" // after "SELECT COUNT(*) FROM USER"
Defensive patterns
Strategy: try-catch
Validate before calling
String sql = countSql.toLowerCase();
if (sql.contains("group by")) throw new IllegalStateException("count SQL must not GROUP BY"); Try / catch
try {
long n = countQuery.count();
} catch (DaoException e) {
if (e.getMessage().startsWith("Unexpected row count")) {
// inspect SQL for GROUP BY/joins producing multiple rows
}
} Prevention
- Keep count SQL a pure aggregate without GROUP BY
- Use buildCount() rather than adapting select queries
- Test count queries after schema/join changes
When it happens
Trigger: The rawQuery returns multiple rows, e.g. the SQL was altered to a GROUP BY select or a non-aggregate query, breaking the single-row COUNT contract.
Common situations: Manually modified count SQL; custom SQLiteCursor implementations; mixing joins that produce grouped rows into a CountQuery.
Related errors
- No result for count
- Unexpected column count:
- Expected unique result, but count was
- Cannot delete entity, key is null
- Entity does not exist in the database anymore
AI-assisted analysis of greenrobot/greenDAO@0bbb338e17 (2026-09-08).
Data as JSON: /api/errors/ccd5112d5dc0b734.
Report an issue: GitHub.
Appendix: source
Thrown at DaoCore/src/main/java/org/greenrobot/greendao/query/CountQuery.java:63
private CountQuery(QueryData<T> queryData, AbstractDao<T, ?> dao, String sql, String[] initialValues) {
super(dao, sql, initialValues);
this.queryData = queryData;
}
public CountQuery<T> forCurrentThread() {
return queryData.forCurrentThread(this);
}
/** Returns the count (number of results matching the query). Uses SELECT COUNT (*) sematics. */
public long count() {
checkThread();
Cursor cursor = dao.getDatabase().rawQuery(sql, parameters);
try {
if (!cursor.moveToNext()) {
throw new DaoException("No result for count");
} else if (!cursor.isLast()) {
throw new DaoException("Unexpected row count: " + cursor.getCount());
} else if (cursor.getColumnCount() != 1) {
throw new DaoException("Unexpected column count: " + cursor.getColumnCount());
}
return cursor.getLong(0);
} finally {
cursor.close();
}
}
// copy setParameter methods to allow easy chaining
@Override
public CountQuery<T> setParameter(int index, Object parameter) {
return (CountQuery<T>) super.setParameter(index, parameter);
}
@Override
public CountQuery<T> setParameter(int index, Date parameter) {
return (CountQuery<T>) super.setParameter(index, parameter);View on GitHub (pinned to 0bbb338e17)