oracle/graal · warning · IllegalArgumentException

OnShutdownCallback value does not have <classname>.<method n

Error message

OnShutdownCallback value does not have <classname>.<method name> format: %s

What it means

At shutdown, if libgraal is in use and HotSpotGraalCompiler.Options.OnShutdownCallback is set, HotSpotGraalRuntime splits the value at the last dot into class and method names. A value with no usable dot (lastDot < 1, or a trailing dot with no method) throws IllegalArgumentException naming the expected <classname>.<method name> format.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalRuntime.java:460

            for (Group group : snippetCounterGroups) {
                TTY.out().out().println(group);
            }
        }
        BenchmarkCounters.shutdown(runtime(), options, runtimeStartTime);

        outputDirectory.close();

        CompilationPrinter.close();

        LibGraalSupport libgraal = LibGraalSupport.INSTANCE;
        if (libgraal != null) {
            String callback = HotSpotGraalCompiler.Options.OnShutdownCallback.getValue(options);
            String callbackClassName = null;
            String callbackMethodName = null;
            if (callback != null) {
                int lastDot = callback.lastIndexOf('.');
                if (lastDot < 1 || lastDot == callback.length() - 1) {
                    throw new IllegalArgumentException(HotSpotGraalCompiler.Options.OnShutdownCallback.getName() + " value does not have <classname>.<method name> format: " + callback);
                }
                callbackClassName = callback.substring(0, lastDot);
                callbackMethodName = callback.substring(lastDot + 1);
            }
            libgraal.shutdown(callbackClassName, callbackMethodName);
        }
    }

    void clearMetrics() {
        metricValues.clear();
    }

    private final boolean bootstrapJVMCI;
    private boolean bootstrapFinished;

    public void notifyBootstrapFinished() {
        bootstrapFinished = true;
    }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Set the value as a fully qualified class plus method: com.foo.ShutdownHook.cleanup (method must be reachable as declared)
  2. Verify the exact string with -Xlog or by printing the property before shutdown
  3. If no callback is needed, unset the option entirely

Example fix

# before
-Dgraal.OnShutdownCallback=cleanup

# after
-Dgraal.OnShutdownCallback=com.foo.ShutdownHooks.cleanup
Defensive patterns

Strategy: validation

Validate before calling

static boolean validCallback(String s) {
    if (s == null) return true;
    int d = s.lastIndexOf('.');
    return d >= 1 && d < s.length() - 1; // class.method, both non-empty
}

Prevention

When it happens

Trigger: Setting -Dgraal.OnShutdownCallback=myscript (no dot), '.mymethod' (empty class), or 'com.foo.Bar.' (empty method) and shutting down a JVM running libgraal; only then is the callback string parsed via lastIndexOf('.') and validated.

Common situations: Using the option to invoke cleanup on shutdown but passing a bare method name or class only; shell quoting/variable expansion eating part of the value; copying the option from docs that omitted the method part.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/aed8b42457dc8d08. Report an issue: GitHub.