diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
index 6717d5517d1c5..928b9a47934af 100644
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java
@@ -277,14 +277,6 @@ int run(String[] args) {
                 return EXIT_OK;
             }
 
-            if (options.modulePath.isEmpty()) {
-                // no --module-path specified - try to set $JAVA_HOME/jmods if that exists
-                Path jmods = getDefaultModulePath();
-                if (jmods != null) {
-                    options.modulePath.add(jmods);
-                }
-            }
-
             JlinkConfiguration config = initJlinkConfig();
             outputPath = config.getOutput();
             if (options.suggestProviders) {
@@ -377,8 +369,13 @@ public static void createImage(JlinkConfiguration config,
     // the token for "all modules on the module path"
     private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
     private JlinkConfiguration initJlinkConfig() throws BadArgs {
+        // Empty module path not allowed with ALL-MODULE-PATH in --add-modules
+        if (options.addMods.contains(ALL_MODULE_PATH) && options.modulePath.isEmpty()) {
+            throw taskHelper.newBadArgs("err.no.module.path");
+        }
         ModuleFinder appModuleFinder = newModuleFinder(options.modulePath);
         ModuleFinder finder = appModuleFinder;
+
         boolean isLinkFromRuntime = false;
         if (!appModuleFinder.find("java.base").isPresent()) {
             // If the application module finder doesn't contain the
@@ -393,8 +390,9 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
             // include the java.base module.
             Path defModPath = getDefaultModulePath();
             if (defModPath != null) {
-                options.modulePath.add(defModPath);
-                finder = newModuleFinder(options.modulePath);
+                List<Path> combinedPaths = new ArrayList<>(options.modulePath);
+                combinedPaths.add(defModPath);
+                finder = newModuleFinder(combinedPaths);
             }
             // We've just added the default module path ('jmods'). If we still
             // don't find java.base, we must resolve JDK modules from the
@@ -419,8 +417,31 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
         Set<String> roots = new HashSet<>();
         for (String mod : options.addMods) {
             if (mod.equals(ALL_MODULE_PATH)) {
-                ModuleFinder mf = newLimitedFinder(finder, options.limitMods,
-                                              Set.of());
+                // Using --limit-modules with ALL-MODULE-PATH is an error
+                if (!options.limitMods.isEmpty()) {
+                    throw taskHelper.newBadArgs("err.limit.modules");
+                }
+                // all observable modules in the app module path are roots
+                Set<String> initialRoots = appModuleFinder.findAll()
+                        .stream()
+                        .map(ModuleReference::descriptor)
+                        .map(ModuleDescriptor::name)
+                        .collect(Collectors.toSet());
+
+                // Error if no module is found on the app module path
+                if (initialRoots.isEmpty()) {
+                    String modPath = options.modulePath.stream()
+                            .map(a -> a.toString())
+                            .collect(Collectors.joining(", "));
+                    throw taskHelper.newBadArgs("err.empty.module.path", modPath);
+                }
+
+                // Use a module finder with limited observability, as determined
+                // by initialRoots, to find the observable modules from the
+                // application module path (--module-path option) only. We must
+                // not include JDK modules from the default module path or the
+                // run-time image.
+                ModuleFinder mf = limitFinder(finder, initialRoots, Set.of());
                 mf.findAll()
                   .stream()
                   .map(ModuleReference::descriptor)
@@ -430,7 +451,7 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs {
                 roots.add(mod);
             }
         }
-        finder = newLimitedFinder(finder, options.limitMods, roots);
+        finder = limitFinder(finder, options.limitMods, roots);
 
         // --keep-packaged-modules doesn't make sense as we are not linking
         // from packaged modules to begin with.
@@ -497,7 +518,7 @@ public static Path getDefaultModulePath() {
      * specified in {@code limitMods} plus other modules specified in the
      * {@code roots} set.
      */
-    public static ModuleFinder newLimitedFinder(ModuleFinder finder,
+    public static ModuleFinder limitFinder(ModuleFinder finder,
                                            Set<String> limitMods,
                                            Set<String> roots) {
         // if limitMods is specified then limit the universe
diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties
index b5880a3556155..a491b758ea0ee 100644
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties
@@ -127,7 +127,9 @@ err.runtime.link.packaged.mods=This JDK has no packaged modules.\
 err.runtime.link.modified.file={0} has been modified
 err.runtime.link.patched.module=jlink does not support linking from the run-time image\
 \ when running on a patched runtime with --patch-module
-err.empty.module.path=empty module path
+err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH
+err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH
+err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH
 err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3}
 err.automatic.module:automatic module cannot be used with jlink: {0} from {1}
 err.unknown.byte.order:unknown byte order {0}
diff --git a/test/jdk/tools/jlink/IntegrationTest.java b/test/jdk/tools/jlink/IntegrationTest.java
index 7f3dc22346106..5a8d0bce15ad7 100644
--- a/test/jdk/tools/jlink/IntegrationTest.java
+++ b/test/jdk/tools/jlink/IntegrationTest.java
@@ -157,7 +157,7 @@ private static void test() throws Exception {
         boolean linkFromRuntime = false;
         JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
                 mods,
-                JlinkTask.newLimitedFinder(JlinkTask.newModuleFinder(modulePaths), limits, mods),
+                JlinkTask.limitFinder(JlinkTask.newModuleFinder(modulePaths), limits, mods),
                 linkFromRuntime,
                 false /* ignore modified runtime */,
                 false /* generate run-time image */);
diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java
index c0fabe06a8c57..0b7de201ac9de 100644
--- a/test/jdk/tools/jlink/JLinkTest.java
+++ b/test/jdk/tools/jlink/JLinkTest.java
@@ -27,17 +27,15 @@
 import java.lang.module.ModuleDescriptor;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.spi.ToolProvider;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
-import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.internal.PluginRepository;
+import jdk.tools.jlink.plugin.Plugin;
 import tests.Helper;
 import tests.JImageGenerator;
 
@@ -135,11 +133,11 @@ public static void main(String[] args) throws Exception {
 
         {
             // No --module-path specified. --add-modules ALL-MODULE-PATH specified.
-            String imageDir = "bug8189777-all-module-path";
+            String imageDir = "bug8345259-all-module-path";
             JImageGenerator.getJLinkTask()
                     .output(helper.createNewImageDir(imageDir))
                     .addMods("ALL-MODULE-PATH")
-                    .call().assertSuccess();
+                    .call().assertFailure();
         }
 
         {
diff --git a/test/jdk/tools/jlink/basic/AllModulePath.java b/test/jdk/tools/jlink/basic/AllModulePath.java
index ba6cc08bd4757..a05f2d06d8658 100644
--- a/test/jdk/tools/jlink/basic/AllModulePath.java
+++ b/test/jdk/tools/jlink/basic/AllModulePath.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,45 +21,52 @@
  * questions.
  */
 
-/*
- * @test
- * @summary jlink test of --add-module ALL-MODULE-PATH
- * @library /test/lib
- * @modules jdk.compiler
- * @build jdk.test.lib.process.ProcessTools
- *        jdk.test.lib.process.OutputAnalyzer
- *        jdk.test.lib.compiler.CompilerUtils
- * @run testng AllModulePath
- */
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
-import java.io.File;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import java.util.spi.ToolProvider;
-
-import jdk.test.lib.compiler.CompilerUtils;
-import jdk.test.lib.process.ProcessTools;
+import java.util.stream.Collectors;
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
-import static org.testng.Assert.*;
 
+import jdk.test.lib.compiler.CompilerUtils;
+import jdk.test.lib.process.ProcessTools;
+import jdk.tools.jlink.internal.LinkableRuntimeImage;
+import tests.Helper;
+import tests.Result;
+
+/*
+ * @test
+ * @bug 8345259
+ * @summary jlink test of --add-module ALL-MODULE-PATH
+ * @library ../../lib /test/lib
+ * @modules jdk.compiler
+ *          java.base/jdk.internal.jimage
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jimage
+ * @build jdk.test.lib.process.ProcessTools
+ *        jdk.test.lib.process.OutputAnalyzer
+ *        jdk.test.lib.compiler.CompilerUtils
+ * @run testng/othervm -Duser.language=en -Duser.country=US AllModulePath
+ */
 public class AllModulePath {
 
-    private final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods");
-    private final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src");
-    private final Path MODS = Paths.get("mods");
+    private static final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods");
+    private static final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src");
+    private static final Path MODS = Paths.get("mods");
+    private static final boolean LINKABLE_RUNTIME = LinkableRuntimeImage.isLinkableRuntime();
+    private static final boolean JMODS_EXIST = Files.exists(JMODS);
 
     private final static Set<String> MODULES = Set.of("test", "m1");
 
@@ -67,12 +74,22 @@ public class AllModulePath {
         .orElseThrow(() ->
             new RuntimeException("jlink tool not found")
         );
+    private static Helper HELPER;
+
+    private static boolean isExplodedJDKImage() {
+        if (!JMODS_EXIST && !LINKABLE_RUNTIME) {
+            System.err.println("Test skipped. Not a linkable runtime and no JMODs");
+            return true;
+        }
+        return false;
+    }
 
     @BeforeClass
     public void setup() throws Throwable {
-        if (Files.notExists(JMODS)) {
+        if (isExplodedJDKImage()) {
             return;
         }
+        HELPER = Helper.newHelper(LINKABLE_RUNTIME);
 
         Files.createDirectories(MODS);
 
@@ -84,60 +101,114 @@ public void setup() throws Throwable {
         }
     }
 
+    /*
+     * --add-modules ALL-MODULE-PATH with an existing module-path.
+     */
     @Test
     public void testAllModulePath() throws Throwable {
-        if (Files.notExists(JMODS)) {
+        if (isExplodedJDKImage()) {
             return;
         }
 
-        // create custom image
-        Path image = Paths.get("image");
-        createImage(image, "--add-modules", "ALL-MODULE-PATH");
+        Path image = HELPER.createNewImageDir("image");
+        List<String> opts = List.of("--module-path", MODS.toString(),
+                                    "--output", image.toString(),
+                                    "--add-modules", "ALL-MODULE-PATH");
+        createImage(image, opts, true /* success */);
 
         Set<String> modules = new HashSet<>();
-        Files.find(JMODS, 1, (Path p, BasicFileAttributes attr) ->
-                                p.toString().endsWith(".jmod"))
-             .map(p -> JMODS.relativize(p).toString())
-             .map(n -> n.substring(0, n.length()-5))
-             .forEach(modules::add);
+        // java.base is a dependency of any external module
+        modules.add("java.base");
         modules.add("m1");
         modules.add("test");
         checkModules(image, modules);
     }
 
+    /*
+     * --add-modules ALL-MODULE-PATH with --limit-modules is an error
+     */
     @Test
     public void testLimitModules() throws Throwable {
-        if (Files.notExists(JMODS)) {
+        if (isExplodedJDKImage()) {
             return;
         }
-
-        // create custom image
-        Path image = Paths.get("image1");
-        createImage(image,
-                    "--add-modules", "ALL-MODULE-PATH",
-                    "--limit-modules", "m1");
-
-        checkModules(image, Set.of("m1", "java.base"));
+        Path targetPath = HELPER.createNewImageDir("all-mods-limit-mods");
+        String moduleName = "com.baz.runtime";
+        Result result = HELPER.generateDefaultJModule(moduleName, "jdk.jfr");
+        Path customModulePath = result.getFile().getParent();
+        List<String> allArgs = List.of("--add-modules", "ALL-MODULE-PATH",
+                                       "--limit-modules", "jdk.jfr",
+                                       "--module-path", customModulePath.toString(),
+                                       "--output", targetPath.toString());
+        JlinkOutput allOut = createImage(targetPath, allArgs, false /* success */);
+        String actual = allOut.stdout.trim();
+        String expected = "Error: --limit-modules not allowed with --add-modules ALL-MODULE-PATH";
+        assertEquals(actual, expected);
     }
 
+
+    /*
+     * --add-modules *includes* ALL-MODULE-PATH with an existing module path
+     */
     @Test
     public void testAddModules() throws Throwable {
-        if (Files.notExists(JMODS)) {
+        if (isExplodedJDKImage()) {
             return;
         }
 
         // create custom image
-        Path image = Paths.get("image2");
-        createImage(image,
-                    "--add-modules", "m1,test",
-                    "--add-modules", "ALL-MODULE-PATH",
-                    "--limit-modules", "java.base");
+        Path image = HELPER.createNewImageDir("image2");
+        List<String> opts = List.of("--module-path", MODS.toString(),
+                                    "--output", image.toString(),
+                                    "--add-modules", "m1",
+                                    "--add-modules", "ALL-MODULE-PATH");
+        createImage(image, opts, true /* success */);
 
         checkModules(image, Set.of("m1", "test", "java.base"));
     }
 
     /*
-     * check the modules linked in the image
+     * No --module-path with --add-modules ALL-MODULE-PATH is an error.
+     */
+    @Test
+    public void noModulePath() throws IOException {
+        if (isExplodedJDKImage()) {
+            return;
+        }
+        Path targetPath = HELPER.createNewImageDir("all-mod-path-no-mod-path");
+        List<String> allArgs = List.of("--add-modules", "ALL-MODULE-PATH",
+                                       "--output", targetPath.toString());
+        JlinkOutput allOut = createImage(targetPath, allArgs, false /* expect failure */);
+        String expected = "Error: --module-path option must be specified with --add-modules ALL-MODULE-PATH";
+        assertEquals(allOut.stdout.trim(), expected);
+    }
+
+    /*
+     * --module-path not-exist and --add-modules ALL-MODULE-PATH is an error.
+     */
+    @Test
+    public void modulePathEmpty() throws IOException {
+        if (isExplodedJDKImage()) {
+            return;
+        }
+        Path targetPath = HELPER.createNewImageDir("all-mod-path-not-existing");
+        String strNotExists = "not-exist";
+        Path notExists = Path.of(strNotExists);
+        if (Files.exists(notExists)) {
+            throw new AssertionError("Test setup error, path must not exist!");
+        }
+        List<String> allArgs = List.of("--add-modules", "ALL-MODULE-PATH",
+                                       "--module-path", notExists.toString(),
+                                       "--output", targetPath.toString());
+
+        JlinkOutput allOut = createImage(targetPath, allArgs, false /* expect failure */);
+        String actual = allOut.stdout.trim();
+        assertTrue(actual.startsWith("Error: No module found in module path"));
+        assertTrue(actual.contains(strNotExists));
+    }
+
+    /*
+     * check the modules linked in the image using m1/p.ListModules
      */
     private void checkModules(Path image, Set<String> modules) throws Throwable {
         Path cmd = findTool(image, "java");
@@ -164,16 +235,19 @@ private Path findTool(Path image, String tool)  {
         return cmd;
     }
 
-    private void createImage(Path image, String... options) throws IOException {
-        String modulepath = JMODS.toString() + File.pathSeparator + MODS.toString();
-        List<String> opts = List.of("--module-path", modulepath,
-                                    "--output", image.toString());
-        String[] args = Stream.concat(opts.stream(), Arrays.stream(options))
-                              .toArray(String[]::new);
-
-        System.out.println("jlink " + Arrays.stream(args).collect(Collectors.joining(" ")));
-        PrintWriter pw = new PrintWriter(System.out);
-        int rc = JLINK_TOOL.run(pw, pw, args);
-        assertTrue(rc == 0);
+    private JlinkOutput createImage(Path image, List<String> args, boolean success) throws IOException {
+        System.out.println("jlink " + args.stream().collect(Collectors.joining(" ")));
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintWriter out = new PrintWriter(baos);
+        ByteArrayOutputStream berrOs = new ByteArrayOutputStream();
+        PrintWriter err = new PrintWriter(berrOs);
+        int rc = JLINK_TOOL.run(out, err, args.toArray(String[]::new));
+        String stdOut = new String(baos.toByteArray());
+        String stdErr = new String(berrOs.toByteArray());
+        assertEquals(rc == 0, success, String.format("Output was: %nstdout: %s%nstderr: %s%n", stdOut, stdErr));
+        return new JlinkOutput(stdErr, stdOut);
     }
+
+    private static record JlinkOutput(String stderr, String stdout) {};
 }
diff --git a/test/jdk/tools/jlink/basic/BasicTest.java b/test/jdk/tools/jlink/basic/BasicTest.java
index a771d4d000250..1a14e620fa626 100644
--- a/test/jdk/tools/jlink/basic/BasicTest.java
+++ b/test/jdk/tools/jlink/basic/BasicTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,21 +21,6 @@
  * questions.
  */
 
-/*
- * @test
- * @summary Basic test of jlink to create jmods and images
- * @author Andrei Eremeev
- * @library /test/lib
- * @modules java.base/jdk.internal.module
- *          jdk.jlink
- *          jdk.compiler
- * @build jdk.test.lib.process.ProcessTools
- *        jdk.test.lib.process.OutputAnalyzer
- *        jdk.test.lib.compiler.CompilerUtils
- *        jdk.test.lib.util.JarUtils
- * @run main BasicTest
- */
-
 import java.io.File;
 import java.io.PrintWriter;
 import java.nio.file.Files;
@@ -50,7 +35,22 @@
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.process.ProcessTools;
 import jdk.test.lib.util.JarUtils;
+import jdk.tools.jlink.internal.LinkableRuntimeImage;
 
+/*
+ * @test
+ * @summary Basic test of jlink to create jmods and images
+ * @author Andrei Eremeev
+ * @library /test/lib
+ * @modules java.base/jdk.internal.module
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.compiler
+ * @build jdk.test.lib.process.ProcessTools
+ *        jdk.test.lib.process.OutputAnalyzer
+ *        jdk.test.lib.compiler.CompilerUtils
+ *        jdk.test.lib.util.JarUtils
+ * @run main/othervm BasicTest
+ */
 public class BasicTest {
     static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
         .orElseThrow(() ->
@@ -62,21 +62,31 @@ public class BasicTest {
             new RuntimeException("jlink tool not found")
         );
 
-    private final String TEST_MODULE = "test";
-    private final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
-    private final Path jdkMods = jdkHome.resolve("jmods");
-    private final Path testSrc = Paths.get(System.getProperty("test.src"));
-    private final Path src = testSrc.resolve("src").resolve(TEST_MODULE);
-    private final Path classes = Paths.get("classes");
-    private final Path jmods = Paths.get("jmods");
-    private final Path jars = Paths.get("jars");
+    private static final String TEST_MODULE = "test";
+    private static final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
+    private static final Path jdkMods = jdkHome.resolve("jmods");
+    private static final boolean JMODS_EXIST = Files.exists(jdkMods);
+    private static final boolean LINKABLE_RUNTIME = LinkableRuntimeImage.isLinkableRuntime();
+    private static final Path testSrc = Paths.get(System.getProperty("test.src"));
+    private static final Path src = testSrc.resolve("src").resolve(TEST_MODULE);
+    private static final Path classes = Paths.get("classes");
+    private static final Path jmods = Paths.get("jmods");
+    private static final Path jars = Paths.get("jars");
 
     public static void main(String[] args) throws Throwable {
         new BasicTest().run();
     }
 
+    private static boolean isExplodedJDKImage() {
+        if (!JMODS_EXIST && !LINKABLE_RUNTIME) {
+            System.err.println("Test skipped. Not a linkable runtime and no JMODs");
+            return true;
+        }
+        return false;
+    }
+
     public void run() throws Throwable {
-        if (Files.notExists(jdkMods)) {
+        if (isExplodedJDKImage()) {
             return;
         }
 
@@ -146,8 +156,10 @@ private void execute(Path image, String scriptName) throws Throwable {
 
     private void runJlink(Path image, String modName, String... options) {
         List<String> args = new ArrayList<>();
+        String modPathArg = (JMODS_EXIST ? jdkMods + File.pathSeparator : "") +
+                                jmods;
         Collections.addAll(args,
-                "--module-path", jdkMods + File.pathSeparator + jmods,
+                "--module-path", modPathArg,
                 "--add-modules", modName,
                 "--output", image.toString());
         Collections.addAll(args, options);