greenrobot/greenDAO · error · DaoException
Method may be called only in owner thread, use…
Error message
Method may be called only in owner thread, use forCurrentThread to get an instance for this thread
What it means
greenDAO Query objects are bound to the thread that created them (ownerThread). checkThread() throws DaoException if any mutation (setParameter, setLimit, etc.) is invoked from another thread. This protects internal parameter arrays from cross-thread mutation.
Solutions
- Call query.forCurrentThread() to obtain a thread-local copy before mutating or executing
- Create a fresh Query in the thread that will use it
- Instead of setParameter, use the thread-safe variant that takes and re-binds via forCurrentThread with new parameter values
Example fix
// before Query<User> query = userDao.queryBuilder().build(); // created on thread A // later on thread B query.setParameter(0, "foo"); // throws // after Query<User> query = userDao.queryBuilder().build(); Query<User> queryForThisThread = query.forCurrentThread(); queryForThisThread.setParameter(0, "foo");
Defensive patterns
Strategy: type-guard
Validate before calling
if (query.getOwnerThread() != Thread.currentThread()) {
query = query.forCurrentThread();
} Type guard
function isOwnerThread(query) { return Thread.currentThread() === query.getOwnerThread(); } Try / catch
try {
query.setParameter(index, value);
} catch (DaoException e) {
if (e.getMessage().contains("forCurrentThread")) {
query = query.forCurrentThread();
query.setParameter(index, value);
}
} Prevention
- Always call forCurrentThread() before reusing a cached Query
- Create queries in the same thread that executes them
- Avoid storing Query instances in shared singletons
- On Android, obtain per-thread queries inside the worker/AsyncTask
When it happens
Trigger: Creating a Query on a background/loader thread and later calling setParameter/setLimit/setOffset on it from a different thread (e.g. UI thread or an AsyncTask worker differing from the creator).
Common situations: Caching a Query in a singleton and reusing it across threads; using the same Query in multiple AsyncTask executions; Android loader vs UI thread mismatches.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Duplicate property ordinals
- Unsupported type
- Table alias required
- Illegal parameter index:
- Limit must be set with QueryBuilder before it can be used…
AI-assisted analysis of greenrobot/greenDAO@0bbb338e17 (2026-09-08).
Data as JSON: /api/errors/f97e67820ee6fd9d.
Report an issue: GitHub.
Appendix: source
Thrown at DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQuery.java:99
/**
* @see #setParameter(int, Object)
*/
public AbstractQuery<T> setParameter(int index, Date parameter) {
Long converted = parameter != null ? parameter.getTime() : null;
return setParameter(index, converted);
}
/**
* @see #setParameter(int, Object)
*/
public AbstractQuery<T> setParameter(int index, Boolean parameter) {
Integer converted = parameter != null ? (parameter ? 1 : 0) : null;
return setParameter(index, converted);
}
protected void checkThread() {
if (Thread.currentThread() != ownerThread) {
throw new DaoException(
"Method may be called only in owner thread, use forCurrentThread to get an instance for this thread");
}
}
}
View on GitHub (pinned to 0bbb338e17)