pinpoint-apm/pinpoint · error · HBaseAccessException
Already closed
Error message
Already closed
What it means
HbaseTemplate tracks its lifecycle with an AtomicBoolean isClose, set when close() is called. assertAccessAvailable(), invoked at the start of execute(), findParallel(), executeDistributedScan() and executeParallelDistributedScan(), throws HBaseAccessException('Already closed') if the template was closed, preventing reads/writes through a dead template.
Source
Thrown at commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate.java:175
return ExecutorFactory.newFixedThreadPool(this.maxThreads, 1024 * 4, threadFactory);
}
}
@Override
public void destroy() throws Exception {
if (isClose.compareAndSet(false, true)) {
logger.info("HBaseTemplate.destroy()");
final ExecutorService executor = this.executor;
if (executor != null) {
MoreExecutors.shutdownAndAwaitTermination(executor, Duration.ofSeconds(3));
}
}
}
private void assertAccessAvailable() {
if (isClose.get()) {
throw new HBaseAccessException("Already closed");
}
}
@Override
public <T> T find(TableName tableName, final Scan scan, final ResultsExtractor<T> action) {
return execute(tableName, new TableCallback<>() {
@Override
public T doInTable(Table table) throws Throwable {
try (ResultScanner scanner = table.getScanner(scan)) {
return action.extractData(scanner);
}
}
});
}
@Override
public <T> List<T> find(TableName tableName, final Scan scan, final RowMapper<T> action) {
return find(tableName, scan, new RowMapperResultsExtractor<>(action));View on GitHub (pinned to 744c3d3075)
Solutions
- Fix the lifecycle so the template is closed only after all dependent tasks finish (e.g. await executor shutdown before closing the context)
- Obtain a fresh HbaseTemplate (or reinitialize the closed one) instead of reusing the closed instance
- Catch HBaseAccessException and skip/queue the operation if the application is intentionally shutting down
Example fix
// before
results = closedTemplate.find(table, scan, extractor); // throws
// after
if (!closedTemplateIsClosed) { // check via try-catch on HBaseAccessException or keep your own state
results = template.find(table, scan, extractor);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Track template lifecycle alongside usage
AtomicBoolean closed = new AtomicBoolean(false);
public <T> T safeFind(HbaseTemplate t, TableName table, Scan scan, ResultsExtractor<T> ex) {
try {
return t.find(table, scan, ex);
} catch (HBaseAccessException e) {
throw new IllegalStateException("Template closed before query", e);
}
} Try / catch
try {
return hbaseTemplate.execute(tableName, tableCallback);
} catch (HBaseAccessException e) {
log.warn("HbaseTemplate already closed, skipping operation: {}", e.getMessage());
return null;
} Prevention
- Shut down schedulers/executors before the Spring context closes HbaseTemplate
- Do not hold HbaseTemplate references in objects that outlive the context
- Treat close() as terminal — recreate a new template bean instead of reusing a closed one
- Centralize HBase access behind one component that checks lifecycle state before queries
When it happens
Trigger: Calling execute(), find/findParallel, or executeDistributedScan on an HbaseTemplate instance after close() was invoked — typically after Spring context shutdown or explicit template close; reusing a cached template bean across application restarts.
Common situations: Async tasks or scheduled jobs holding a reference to the template that keeps running after the container closed it; a service singleton capturing HbaseTemplate before context refresh failure led to close; double-destroy of a lifecycle bean followed by more queries.
Related errors
- Connection already closed
- traceReference is null
- traceReference is null
- startTime not recorded
- Cannot leave with scope. depth: ${depth}
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/f643507b7a29b7cb.
Report an issue: GitHub.