quarkusio/quarkus · error · IllegalStateException
Cannot determine image path (bin path)
Error message
Cannot determine image path (bin path)
What it means
The launcher derives the jlink image root by taking the current process command, expecting its parent directory to be named 'bin' (the standard image layout image/bin/<launcher>). If ProcessHandle returns a command whose parent is missing or not named 'bin', the image path cannot be derived. Note the source also throws a distinct variant 'Cannot determine image path (ProcessHandle)' when the command itself is unavailable.
Source
Thrown at extensions/packaging/jlink/launcher/src/main/java/io/quarkus/jlink/launcher/JLinkAppLauncher.java:44
Module myModule = JLinkAppLauncher.class.getModule();
if (myModule == null) {
throw new IllegalStateException("Must launch jlink image in module mode only");
}
ModuleLayer myLayer = myModule.getLayer();
if (myLayer == null) {
throw new IllegalStateException("Module of jlink image launcher is not in a module layer");
}
@SuppressWarnings("resource")
ModuleLoader base = ModuleLoader.forLayer("base", myLayer);
// try to ascertain our own path
String cmd = ProcessHandle.current().info().command()
.orElseThrow(() -> new IllegalStateException("Cannot determine image path (ProcessHandle)"));
Path cmdPath = Path.of(cmd);
Path binPath = cmdPath.getParent();
if (binPath == null || !binPath.getFileName().toString().equals("bin")) {
throw new IllegalStateException("Cannot determine image path (bin path)");
}
Path imagePath = binPath.getParent();
if (imagePath == null) {
throw new IllegalStateException("Cannot determine image path (image path)");
}
Path libPath = imagePath.resolve("lib").resolve("quarkus");
// create a layer for our dynamic modules
ModuleLoader dyn = new ModuleLoader("dyn", ModuleFinder.fromFileSystem(List.of(libPath))) {
public LoadedModule loadModule(final String moduleName) {
LoadedModule found = base.loadModule(moduleName);
if (found == null) {
found = super.loadModule(moduleName);
}
return found;
}
};View on GitHub (pinned to e1c734241f)
Solutions
- Run the launcher from the image's bin/ directory via its original path (image/bin/<name>)
- Avoid symlinking or moving the launcher binary; symlink the image root instead so layout stays image/bin/<launcher>
- Keep the standard jlink image layout (bin/ as direct parent of the executable)
- Check ProcessHandle command output if in a container and ensure the executable path is preserved
Example fix
// before: moved/wrapped launcher /usr/local/bin/myapp-launcher.sh // after: invoke in place /opt/myapp-image/bin/myapp
Defensive patterns
Strategy: validation
Validate before calling
Path cmd = ProcessHandle.current().info().command()
.map(Path::of).orElse(null);
if (cmd == null || cmd.getParent() == null
|| !"bin".equals(cmd.getParent().getFileName().toString())) {
throw new IllegalStateException("Launcher must reside at <image>/bin/<name>");
} Type guard
boolean isInsideImageBin(Path executable) {
Path parent = executable.getParent();
return parent != null && "bin".equals(parent.getFileName().toString());
} Try / catch
try {
JLinkAppLauncher.run(appModule, args);
} catch (IllegalStateException e) {
if (e.getMessage().contains("image path")) {
throw new IllegalStateException("Run the launcher from the image's bin/ directory", e);
}
throw e;
} Prevention
- Never move, copy, or wrap the launcher binary outside bin/
- Symlink the image root, not individual executables
- Keep the standard jlink image layout in containers
When it happens
Trigger: The launcher binary is invoked via a symlink, wrapper script, or a path whose parent directory is not literally named 'bin'; the process command is an interpreter or relative path so getParent() is not the image bin directory.
Common situations: Copying the launcher out of bin/ to run it elsewhere; invoking through a shell wrapper in a different directory; container images that flatten or rename the bin directory; running the classpath test harness that simulates the launcher.
Related errors
- Cannot determine image path (image path)
- Must launch jlink image in module mode only
- Module of jlink image launcher is not in a module layer
- Unable to find command: %s in $PATH: %s
- Docker Compose not found. Is ${composeExecutable} on the PAT
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/0c70348fe38032a2.
Report an issue: GitHub.