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

  1. Ensure the count query SQL contains no GROUP BY and is a pure aggregate select
  2. Rebuild via buildCount() rather than reusing a regular Query's SQL
  3. 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

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


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)