apache/flink · warning · IOException

Could not un-export our RMI registry

Error message

Could not un-export our RMI registry

What it means

JMXServer.stop() shuts down the JMX connector server and then un-exports the RMI registry via UnicastRemoteObject.unexportObject. If that call throws NoSuchObjectException (the registry object is no longer exported — already unexported, garbage-collected, or shut down elsewhere), it is wrapped in IOException('Could not un-export our RMI registry'). It occurs during teardown, after the connector itself was stopped.

Source

Thrown at flink-core/src/main/java/org/apache/flink/management/jmx/JMXServer.java:80

        }
        internalStart(port);
        this.port = port;
    }

    void stop() throws IOException {
        rmiServerReference.set(null);
        if (connector != null) {
            try {
                connector.stop();
            } finally {
                connector = null;
            }
        }
        if (rmiRegistry != null) {
            try {
                UnicastRemoteObject.unexportObject(rmiRegistry, true);
            } catch (NoSuchObjectException e) {
                throw new IOException("Could not un-export our RMI registry", e);
            } finally {
                rmiRegistry = null;
            }
        }
    }

    int getPort() {
        return port;
    }

    private void internalStart(int port) throws IOException {
        rmiServerReference.set(null);

        // this allows clients to lookup the JMX service
        rmiRegistry = new JmxRegistry(port, "jmxrmi", rmiServerReference);

        String serviceUrl =
                "service:jmx:rmi://localhost:" + port + "/jndi/rmi://localhost:" + port + "/jmxrmi";

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Make stop() idempotent in calling code: null-check / set a stopped flag so it runs once.
  2. Treat this IOException during shutdown as benign when the JVM/process is exiting anyway: catch and log at debug.
  3. If you restart JMX servers repeatedly, create a fresh JMXServer instance per start rather than reusing one.

Example fix

// before
jmxServer.stop(); // called from both shutdown hook and close()

// after
if (!stopped) {
    stopped = true;
    jmxServer.stop();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!stopped) {
    stopped = true;
    jmxServer.stop();
}

Try / catch

try {
    jmxServer.stop();
} catch (IOException e) {
    if (e.getCause() instanceof NoSuchObjectException) {
        // registry already unexported; safe to ignore during shutdown
        LOG.debug("JMX registry already unexported", e);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling stop() twice on a JMXServer; a prior stop or an RMI-internal cleanup that already unexported the registry; JVM shutdown racing the explicit stop().

Common situations: Re-starting an embedded JMX server in tests (stop then start again) where the second stop finds the registry gone; shutdown hooks and explicit close both invoking stop(); RMI DGC collecting the registry between start and stop.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/880a417cca59cc7a. Report an issue: GitHub.