{"record":{"id":"0c70348fe38032a2","repo":"quarkusio/quarkus","slug":"cannot-determine-image-path-bin-path","errorCode":null,"errorMessage":"Cannot determine image path (bin path)","messagePattern":"Cannot determine image path \\(bin path\\)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/packaging/jlink/launcher/src/main/java/io/quarkus/jlink/launcher/JLinkAppLauncher.java","lineNumber":44,"sourceCode":"        Module myModule = JLinkAppLauncher.class.getModule();\n        if (myModule == null) {\n            throw new IllegalStateException(\"Must launch jlink image in module mode only\");\n        }\n        ModuleLayer myLayer = myModule.getLayer();\n        if (myLayer == null) {\n            throw new IllegalStateException(\"Module of jlink image launcher is not in a module layer\");\n        }\n\n        @SuppressWarnings(\"resource\")\n        ModuleLoader base = ModuleLoader.forLayer(\"base\", myLayer);\n\n        // try to ascertain our own path\n        String cmd = ProcessHandle.current().info().command()\n                .orElseThrow(() -> new IllegalStateException(\"Cannot determine image path (ProcessHandle)\"));\n        Path cmdPath = Path.of(cmd);\n        Path binPath = cmdPath.getParent();\n        if (binPath == null || !binPath.getFileName().toString().equals(\"bin\")) {\n            throw new IllegalStateException(\"Cannot determine image path (bin path)\");\n        }\n        Path imagePath = binPath.getParent();\n        if (imagePath == null) {\n            throw new IllegalStateException(\"Cannot determine image path (image path)\");\n        }\n\n        Path libPath = imagePath.resolve(\"lib\").resolve(\"quarkus\");\n\n        // create a layer for our dynamic modules\n        ModuleLoader dyn = new ModuleLoader(\"dyn\", ModuleFinder.fromFileSystem(List.of(libPath))) {\n            public LoadedModule loadModule(final String moduleName) {\n                LoadedModule found = base.loadModule(moduleName);\n                if (found == null) {\n                    found = super.loadModule(moduleName);\n                }\n                return found;\n            }\n        };","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/packaging/jlink/launcher/src/main/java/io/quarkus/jlink/launcher/JLinkAppLauncher.java#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: moved/wrapped launcher\n/usr/local/bin/myapp-launcher.sh\n// after: invoke in place\n/opt/myapp-image/bin/myapp","handlingStrategy":"validation","validationCode":"Path cmd = ProcessHandle.current().info().command()\n        .map(Path::of).orElse(null);\nif (cmd == null || cmd.getParent() == null\n        || !\"bin\".equals(cmd.getParent().getFileName().toString())) {\n    throw new IllegalStateException(\"Launcher must reside at <image>/bin/<name>\");\n}","typeGuard":"boolean isInsideImageBin(Path executable) {\n    Path parent = executable.getParent();\n    return parent != null && \"bin\".equals(parent.getFileName().toString());\n}","tryCatchPattern":"try {\n    JLinkAppLauncher.run(appModule, args);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"image path\")) {\n        throw new IllegalStateException(\"Run the launcher from the image's bin/ directory\", e);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["jlink","launcher","path"],"backgroundTag":"image-layout-violation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}