greenrobot/greenDAO · error · DaoException
Expected unique result, but count was
Error message
Expected unique result, but count was ${cursor.getCount()} What it means
greenDAO's loadUnique(Cursor) expects a query that returns at most one row. If the cursor is positioned on the first row but isLast() is false, more than one row matched, so it throws DaoException. This protects API contracts where the caller assumes a unique result.
Solutions
- Make the query condition actually unique (query by primary key or a column with a UNIQUE index).
- Use query().list()/listIterator() instead of loadUnique if multiple rows are legitimate.
- Deduplicate existing data with DELETE/UPDATE so at most one row matches the condition.
- Add a UNIQUE constraint to the column so duplicates cannot be inserted (with schema migration).
Example fix
// before User u = userDao.queryBuilder().where(UserDao.Properties.Email.eq(email)).unique(); // after (column not guaranteed unique — handle list) List<User> users = userDao.queryBuilder().where(UserDao.Properties.Email.eq(email)).list(); User u = users.isEmpty() ? null : users.get(0);
Defensive patterns
Strategy: validation
Validate before calling
long count = userDao.queryBuilder().where(Properties.Email.eq(email)).buildCount().count();
if (count > 1) throw new IllegalStateException("Duplicate rows for email: " + email); Try / catch
try {
User u = userDao.queryBuilder().where(Properties.Email.eq(email)).unique();
// use u (may be null)
} catch (DaoException e) {
// multiple rows matched: fall back to list query and pick/dedupe
List<User> all = userDao.queryBuilder().where(Properties.Email.eq(email)).list();
} Prevention
- Add UNIQUE constraints to columns used with .unique()/loadUnique.
- Prefer load(pk) for primary-key lookups.
- Deduplicate data after migrations.
- Use list() when uniqueness is not schema-guaranteed.
When it happens
Trigger: Calling loadUnique()/loadUniqueAndCloseCursor() on a query whose WHERE clause matches more than one row — typically a query on a non-unique column or a queryBuilder whereUnique/where condition that isn't actually unique.
Common situations: Querying by a column assumed unique but not declared UNIQUE in the schema; duplicated rows after a schema migration or manual inserts; using loadUnique where load() by primary key or a list query was intended.
Related errors
- No entity found for query
- Cannot delete entity, key is null
- Entity does not exist in the database anymore
- Cannot update entity without key - was it inserted before?
- ( ) does not have a single-column primary key
AI-assisted analysis of greenrobot/greenDAO@0bbb338e17 (2026-09-08).
Data as JSON: /api/errors/b54527c247fdf47c.
Report an issue: GitHub.
Appendix: source
Thrown at DaoCore/src/main/java/org/greenrobot/greendao/AbstractDao.java:170
String[] idArray = new String[]{Long.toString(rowId)};
Cursor cursor = db.rawQuery(statements.getSelectByRowId(), idArray);
return loadUniqueAndCloseCursor(cursor);
}
protected T loadUniqueAndCloseCursor(Cursor cursor) {
try {
return loadUnique(cursor);
} finally {
cursor.close();
}
}
protected T loadUnique(Cursor cursor) {
boolean available = cursor.moveToFirst();
if (!available) {
return null;
} else if (!cursor.isLast()) {
throw new DaoException("Expected unique result, but count was " + cursor.getCount());
}
return loadCurrent(cursor, 0, true);
}
/** Loads all available entities from the database. */
public List<T> loadAll() {
Cursor cursor = db.rawQuery(statements.getSelectAll(), null);
return loadAllAndCloseCursor(cursor);
}
/** Detaches an entity from the identity scope (session). Subsequent query results won't return this object. */
public boolean detach(T entity) {
if (identityScope != null) {
K key = getKeyVerified(entity);
return identityScope.detach(key, entity);
} else {
return false;
}View on GitHub (pinned to 0bbb338e17)