apache/pulsar · error · IllegalStateException
Connector is already closed
Error message
Connector is already closed
What it means
Connector wraps a connector (source/sink) NAR package and is closeable; its private checkState() throws this IllegalStateException when any accessor is used after close(). Methods like getConnectorFunctionPackage(), getSourceConfigFieldDefinitions() and getSinkConfigFieldDefinitions() call checkState() first to prevent use of a closed connector archive.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/io/Connector.java:89
}
public String getArchiveChecksumHex() {
return archiveChecksumHex;
}
public synchronized ValidatableFunctionPackage getConnectorFunctionPackage() {
checkState();
if (connectorFunctionPackage == null) {
connectorFunctionPackage =
new FunctionFilePackage(archivePath.toFile(), narExtractionDirectory, enableClassloading,
ConnectorDefinition.class);
}
return connectorFunctionPackage;
}
private void checkState() {
if (closed) {
throw new IllegalStateException("Connector is already closed");
}
}
public synchronized List<ConfigFieldDefinition> getSourceConfigFieldDefinitions() {
checkState();
if (sourceConfigFieldDefinitions == null && !StringUtils.isEmpty(connectorDefinition.getSourceClass())
&& !StringUtils.isEmpty(connectorDefinition.getSourceConfigClass())) {
sourceConfigFieldDefinitions = ConnectorUtils.getConnectorConfigDefinition(getConnectorFunctionPackage(),
connectorDefinition.getSourceConfigClass());
}
return sourceConfigFieldDefinitions;
}
public synchronized List<ConfigFieldDefinition> getSinkConfigFieldDefinitions() {
checkState();
if (sinkConfigFieldDefinitions == null && !StringUtils.isEmpty(connectorDefinition.getSinkClass())
&& !StringUtils.isEmpty(connectorDefinition.getSinkConfigClass())) {
sinkConfigFieldDefinitions = ConnectorUtils.getConnectorConfigDefinition(getConnectorFunctionPackage(),View on GitHub (pinned to 820761864e)
Solutions
- Obtain a fresh Connector instance from the connector definitions loader rather than using the closed one.
- Ensure close() is only called after all readers finish (or synchronize reload with usage).
- In custom code, re-open the Connector when isClosed() is true instead of reusing the handle.
Example fix
// before Connector connector = loader.loadConnector(def, narDir, false); // ... reload closed it List<ConfigFieldDefinition> defs = connector.getSinkConfigFieldDefinitions(); // IllegalStateException // after connector = loader.loadConnector(def, narDir, false); // re-resolve before use List<ConfigFieldDefinition> defs = connector.getSinkConfigFieldDefinitions();
Defensive patterns
Strategy: try-catch
Validate before calling
if (connector.isClosed()) {
connector = connectorLoader.loadConnector(connectorDefinition, narExtractionDirectory, false); // re-resolve
} Try / catch
try {
List<ConfigFieldDefinition> defs = connector.getSinkConfigFieldDefinitions();
} catch (IllegalStateException e) {
if (e.getMessage().contains("already closed")) {
connector = connectorLoader.loadConnector(connectorDefinition, narExtractionDirectory, false);
List<ConfigFieldDefinition> defs = connector.getSinkConfigFieldDefinitions();
} else {
throw e;
}
} Prevention
- Fetch connector config definitions through a loader that always returns a live Connector instance.
- Avoid long-lived caching of Connector handles across connector reloads.
- Scope Connector lifetime tightly (open, use, close) within a single operation.
When it happens
Trigger: Calling getConnectorFunctionPackage(), getSourceConfigFieldDefinitions(), or getSinkConfigFieldDefinitions() after Connector.close() was invoked — e.g. during connector reload/eviction on the worker while another thread still holds the old Connector instance.
Common situations: Reload race: built-in connector NARs reloaded (closing old Connector objects) while validation code still uses a previously obtained Connector; custom tooling caching a Connector and reading config field definitions after closing it; long-lived references surviving an admin-triggered reconfiguration.
Related errors
- FunctionArchive is already closed
- The log error handler cannot be changed once the appender is
- javaInstanceRunnable is not initialized
- %s package does not have the correct format. Pulsar cannot d
- The '%s' connector does not provide a source implementation
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/c083b7caf571d63f.
Report an issue: GitHub.