apache/seatunnel · error · RuntimeException
Unsafe invoke, the current thread[%s] has not acquired the l
Error message
Unsafe invoke, the current thread[%s] has not acquired the lock[%s].
What it means
SplitFetcher methods suffixed 'Unsafe' (getNextTaskUnsafe) must only be called while holding the fetcher's ReentrantLock. getNextTaskUnsafe explicitly checks lock.isHeldByCurrentThread() and throws if the calling thread does not own the lock, guarding internal task-queue state from unsynchronized access.
Source
Thrown at seatunnel-connectors-v2/connector-common/src/main/java/org/apache/seatunnel/connectors/seatunnel/common/source/reader/fetcher/SplitFetcher.java:183
String.format(
"SplitFetcher thread %d received unexpected exception while polling the records",
fetcherId),
e);
}
// re-acquire lock as all post-processing steps, need it
lock.lock();
try {
this.runningTask = null;
} finally {
lock.unlock();
}
return true;
}
private SplitFetcherTask getNextTaskUnsafe() {
if (!lock.isHeldByCurrentThread()) {
throw new RuntimeException(
String.format(
"Unsafe invoke, the current thread[%s] has not acquired the lock[%s].",
Thread.currentThread().getName(), this.lock.toString()));
}
try {
if (!taskQueue.isEmpty()) {
// execute tasks in taskQueue first
return taskQueue.poll();
} else if (!assignedSplits.isEmpty()) {
// use fallback task = fetch if there is at least one split
return fetchTask;
} else {
// nothing to do, wait for signal
nonEmpty.await();
return taskQueue.poll();
}
} catch (InterruptedException e) {View on GitHub (pinned to cf67b549a7)
Solutions
- Acquire the lock before calling: lock.lock() then try { getNextTaskUnsafe(); } finally { lock.unlock(); }
- Don't call Unsafe methods from outside SplitFetcher.run() — use public APIs (addTask, shutdown, wakeUp) which handle locking
- If subclassing SplitFetcher, mirror the original run() locking structure
- Restore the original runOnce()/run() call pattern if a refactor removed lock acquisition
Example fix
// before
splitFetcher.getNextTaskUnsafe(); // wrong thread, no lock
// after
splitFetcher.lock.lock();
try {
splitFetcher.getNextTaskUnsafe();
} finally {
splitFetcher.lock.unlock();
} Defensive patterns
Strategy: type-guard
Validate before calling
// assert ownership before unsafe calls
if (!splitFetcher.lock.isHeldByCurrentThread()) {
throw new AssertionError("must hold SplitFetcher lock before unsafe calls");
} Type guard
boolean canCallUnsafe(SplitFetcher f) {
return f.lock.isHeldByCurrentThread();
} Prevention
- Never call *Unsafe methods from outside SplitFetcher; use public wrappers (addTask, wakeUp, shutdown)
- When subclassing, replicate the original run() lock/unlock structure
- Avoid refactors that separate unsafe calls from their lock acquisition
- Prefer ReentrantLock.isHeldByCurrentThread() assertions in tests for fetcher internals
When it happens
Trigger: Any code path calling getNextTaskUnsafe (directly or via runOnce refactoring) from a thread that has not acquired SplitFetcher's lock — typically new custom code or subclasses touching fetcher internals, since run() normally acquires the lock before runOnce().
Common situations: Custom SplitFetcher subclass overriding run()/runOnce() without wrapping calls in lock.lock()/unlock(); external tooling invoking private-adjacent unsafe methods; concurrency refactors that dropped lock acquisition.
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
- The thread was interrupted while waiting for a fetcher task.
- User does not have the 'LOCK TABLES' privilege required to o
- Source fetch execution was fail
- SplitFetcher thread %d received unexpected exception while p
- The split fetcher manager has closed.
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/edcaeaf61e6422d8.
Report an issue: GitHub.