Fix crash when --package_path contains only non-existent directories

When `--package_path` is set to directories that do not exist (e.g. `--package_path=/notadir`), `PathPackageLocator` previously skipped all missing entries and returned an instance with an empty list of path entries. Subsequent subsystems expecting at least one package path root (such as Skyfocus, execution tooling, and external package helpers) crashed with unhandled runtime exceptions (`NoSuchElementException` or `IndexOutOfBoundsException`).

Validation now ensures `resolvedPaths` is not empty during package locator creation. If no directories exist on disk, Bazel fails fast with an `AbruptExitException` (`FailureDetails.PackageOptions.Code.PACKAGE_PATH_INVALID`, exit code 2) and reports a descriptive error:
```
ERROR: None of the directories specified in --package_path '/notadir' exist
```

Early initialization errors during `workspace.initCommand(...)` are caught and surfaced cleanly by `BlazeCommandDispatcher`.

Fixes https://github.com/bazelbuild/bazel/issues/17774

PiperOrigin-RevId: 972049409
Change-Id: I311bdc07b65b2cb9912312d81dfd7dc6e8309692
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java b/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java
index 21bdc9f..52bec8a 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/PathPackageLocator.java
@@ -138,11 +138,12 @@
   public static String maybeReplaceWorkspaceInString(String pathElement, PathFragment workspace) {
     return pathElement.replace(WORKSPACE_WILDCARD, workspace.getPathString());
   }
+
   /**
    * A factory of PathPackageLocators from a list of path elements. Elements may contain
    * "%workspace%", indicating the workspace.
    *
-   * <p>If any of the paths given do not exist, an exception will be thrown.
+   * <p>If none of the paths given exist, an exception will be thrown.
    *
    * @param outputBase the output base. Can be null if remote repositories are not in use.
    * @param pathElements Each element must be an absolute path, relative path, or some string
@@ -164,7 +165,8 @@
       EventHandler eventHandler,
       PathFragment workspace,
       Path clientWorkingDirectory,
-      List<BuildFileName> buildFilesByPriority) {
+      List<BuildFileName> buildFilesByPriority)
+      throws AbruptExitException {
     return createInternal(
         outputBase,
         pathElements,
@@ -197,7 +199,8 @@
       EventHandler eventHandler,
       PathFragment workspace,
       Path clientWorkingDirectory,
-      List<BuildFileName> buildFilesByPriority) {
+      List<BuildFileName> buildFilesByPriority)
+      throws AbruptExitException {
     List<Root> resolvedPaths = new ArrayList<>();
 
     for (String pathElement : pathElements) {
@@ -228,6 +231,19 @@
       }
     }
 
+    if (resolvedPaths.isEmpty()) {
+      throw new AbruptExitException(
+          DetailedExitCode.of(
+              FailureDetail.newBuilder()
+                  .setMessage(
+                      String.format(
+                          "None of the directories specified in --package_path '%s' exist",
+                          String.join(":", pathElements)))
+                  .setPackageOptions(
+                      FailureDetails.PackageOptions.newBuilder().setCode(Code.PACKAGE_PATH_INVALID))
+                  .build()));
+    }
+
     return new PathPackageLocator(outputBase, resolvedPaths, buildFilesByPriority);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index c1be3c2..b7692a6 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -401,21 +401,30 @@
 
     // The initCommand call also records the start time for the timestamp granularity monitor.
     List<String> commandEnvWarnings = new ArrayList<>();
-    CommandEnvironment env =
-        workspace.initCommand(
-            commandAnnotation,
-            options,
-            invocationPolicy,
-            commandEnvWarnings,
-            waitTimeInMs,
-            firstContactTime,
-            idleTaskResultsFromPreviousIdlePeriod,
-            this::setShutdownReason,
-            commandExtensions,
-            commandExtensionReporter,
-            attemptNumber,
-            buildRequestIdOverride,
-            parseResults.configFlagDefinitions());
+    CommandEnvironment env;
+    try {
+      env =
+          workspace.initCommand(
+              commandAnnotation,
+              options,
+              invocationPolicy,
+              commandEnvWarnings,
+              waitTimeInMs,
+              firstContactTime,
+              idleTaskResultsFromPreviousIdlePeriod,
+              this::setShutdownReason,
+              commandExtensions,
+              commandExtensionReporter,
+              attemptNumber,
+              buildRequestIdOverride,
+              parseResults.configFlagDefinitions());
+    } catch (AbruptExitException e) {
+      if (e.getMessage() != null) {
+        outErr.printErrLn("ERROR: " + e.getMessage());
+      }
+      storedEventHandler.handle(Event.error(e.getMessage()));
+      return BlazeCommandResult.detailedExitCode(e.getDetailedExitCode());
+    }
 
     if (attemptNumber > 1) {
       outErr.printErrLn("Found transient remote cache error, retrying the build...");
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeWorkspace.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeWorkspace.java
index 21bb26d..0f8e02c 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeWorkspace.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeWorkspace.java
@@ -44,6 +44,7 @@
 import com.google.devtools.build.lib.skyframe.serialization.Fingerprinter;
 import com.google.devtools.build.lib.skyframe.serialization.ObjectCodecRegistry;
 import com.google.devtools.build.lib.skyframe.serialization.analysis.RemoteAnalysisCachingServicesSupplier;
+import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.util.io.CommandExtensionReporter;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
@@ -199,9 +200,7 @@
     return runtime;
   }
 
-  /**
-   * Returns the Blaze directories object for this runtime.
-   */
+  /** Returns the Blaze directories object for this runtime. */
   public BlazeDirectories getDirectories() {
     return directories;
   }
@@ -221,17 +220,16 @@
   /**
    * Returns the working directory of the server.
    *
-   * <p>This is often the first entry on the {@code --package_path}, but not always.
-   * Callers should certainly not make this assumption. The Path returned may be null.
+   * <p>This is often the first entry on the {@code --package_path}, but not always. Callers should
+   * certainly not make this assumption. The Path returned may be null.
    */
   public Path getWorkspace() {
     return directories.getWorkingDirectory();
   }
 
   /**
-   * Returns the output base directory associated with this Blaze server
-   * process. This is the base directory for shared Blaze state as well as tool
-   * and strategy specific subdirectories.
+   * Returns the output base directory associated with this Blaze server process. This is the base
+   * directory for shared Blaze state as well as tool and strategy specific subdirectories.
    */
   public Path getOutputBase() {
     return directories.getOutputBase();
@@ -293,9 +291,7 @@
             : null;
   }
 
-  /**
-   * Range that represents the last execution time of a build in millis since epoch.
-   */
+  /** Range that represents the last execution time of a build in millis since epoch. */
   @Nullable
   public Range<Long> getLastExecutionTimeRange() {
     return lastExecutionRange;
@@ -324,7 +320,8 @@
       CommandExtensionReporter commandExtensionReporter,
       int attemptNumber,
       @Nullable String buildRequestIdOverride,
-      ConfigFlagDefinitions configFlagDefinitions) {
+      ConfigFlagDefinitions configFlagDefinitions)
+      throws AbruptExitException {
     quiescingExecutors.resetParameters(options);
     CommandEnvironment env =
         new CommandEnvironment(
@@ -408,9 +405,9 @@
   }
 
   /**
-   * Generates a README file in the output base directory. This README file
-   * contains the name of the workspace directory, so that users can figure out
-   * which output base directory corresponds to which workspace.
+   * Generates a README file in the output base directory. This README file contains the name of the
+   * workspace directory, so that users can figure out which output base directory corresponds to
+   * which workspace.
    */
   private void writeOutputBaseReadmeFile() {
     Preconditions.checkNotNull(getWorkspace());
@@ -490,7 +487,8 @@
   }
 
   @Nullable // Null for commands that don't have PackageOptions (version, help, shutdown, etc).
-  private PathPackageLocator getOrCreatePackageLocatorForCommand(OptionsParsingResult options) {
+  private PathPackageLocator getOrCreatePackageLocatorForCommand(OptionsParsingResult options)
+      throws AbruptExitException {
     var packageOptions = options.getOptions(PackageOptions.class);
     Path workspace = directories.getWorkspace();
     if (packageOptions == null || workspace == null) {
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
index a8b81be..5582705 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
@@ -495,7 +495,7 @@
     assertContainsEvent(expectedError);
   }
 
-  private void setUpSkyframe() {
+  private void setUpSkyframe() throws AbruptExitException {
     PathPackageLocator pkgLocator =
         PathPackageLocator.create(
             outputBase,
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java b/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java
index 6200084..3ba24a4 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/PackageLoadingTestCase.java
@@ -250,7 +250,7 @@
     skyframeExecutor.setActionEnv(ImmutableMap.of());
   }
 
-  private void setUpSkyframe() {
+  private void setUpSkyframe() throws AbruptExitException {
     PathPackageLocator pkgLocator =
         PathPackageLocator.create(
             outputBase,
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/BUILD b/src/test/java/com/google/devtools/build/lib/pkgcache/BUILD
index 771057c..d506074 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/BUILD
@@ -239,9 +239,9 @@
     srcs = ["PathPackageLocatorTest.java"],
     deps = [
         "//src/main/java/com/google/devtools/build/lib/cmdline",
-        "//src/main/java/com/google/devtools/build/lib/packages",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
         "//src/main/java/com/google/devtools/build/lib/skyframe:skyframe_cluster",
+        "//src/main/java/com/google/devtools/build/lib/util:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/protobuf:failure_details_java_proto",
         "//src/test/java/com/google/devtools/build/lib/testutil",
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java
index cb66be8..0370758 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java
@@ -45,7 +45,6 @@
 import com.google.devtools.build.lib.vfs.SyscallCache;
 import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
 import com.google.devtools.common.options.OptionsParser;
-import com.google.devtools.common.options.OptionsParsingException;
 import java.nio.charset.StandardCharsets;
 import java.util.UUID;
 import java.util.logging.Level;
@@ -55,9 +54,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/**
- * Tests for package loading.
- */
+/** Tests for package loading. */
 @RunWith(JUnit4.class)
 public class BuildFileModificationTest extends FoundationTestCase {
 
@@ -71,7 +68,7 @@
   }
 
   @Before
-  public final void initializeSkyframeExecutor() throws OptionsParsingException {
+  public final void initializeSkyframeExecutor() throws Exception {
     AnalysisMock analysisMock = AnalysisMock.getAnalysisMockWithoutBuiltinModules();
     ConfiguredRuleClassProvider ruleClassProvider = analysisMock.createRuleClassProvider();
     BlazeDirectories directories =
@@ -104,7 +101,7 @@
   }
 
   private void setUpSkyframe(
-      PackageOptions packageOptions, BuildLanguageOptions buildLanguageOptions) {
+      PackageOptions packageOptions, BuildLanguageOptions buildLanguageOptions) throws Exception {
     PathPackageLocator pkgLocator =
         PathPackageLocator.create(
             null,
@@ -141,8 +138,9 @@
 
   private Package getPackage(String packageName)
       throws NoSuchPackageException, InterruptedException {
-    return skyframeExecutor.getPackageManager().getPackage(reporter,
-        PackageIdentifier.createInMainRepo(packageName));
+    return skyframeExecutor
+        .getPackageManager()
+        .getPackage(reporter, PackageIdentifier.createInMainRepo(packageName));
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java
index 2e176f4..2139143 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunnerTest.java
@@ -1635,32 +1635,32 @@
 
   @Test
   public void testPackageLoadingError_keepGoing_explicitTarget() throws Exception {
-    runTestPackageLoadingError(/*keepGoing=*/ true, "//bad:BUILD");
+    runTestPackageLoadingError(/* keepGoing= */ true, "//bad:BUILD");
   }
 
   @Test
   public void testPackageLoadingError_noKeepGoing_explicitTarget() throws Exception {
-    runTestPackageLoadingError(/*keepGoing=*/ false, "//bad:BUILD");
+    runTestPackageLoadingError(/* keepGoing= */ false, "//bad:BUILD");
   }
 
   @Test
   public void testPackageLoadingError_keepGoing_targetsInPackage() throws Exception {
-    runTestPackageLoadingError(/*keepGoing=*/ true, "//bad:all");
+    runTestPackageLoadingError(/* keepGoing= */ true, "//bad:all");
   }
 
   @Test
   public void testPackageLoadingError_noKeepGoing_targetsInPackage() throws Exception {
-    runTestPackageLoadingError(/*keepGoing=*/ false, "//bad:all");
+    runTestPackageLoadingError(/* keepGoing= */ false, "//bad:all");
   }
 
   @Test
   public void testPackageLoadingError_keepGoing_targetsBeneathDirectory() throws Exception {
-    runTestPackageLoadingError(/*keepGoing=*/ true, "//bad/...");
+    runTestPackageLoadingError(/* keepGoing= */ true, "//bad/...");
   }
 
   @Test
   public void testPackageLoadingError_noKeepGoing_targetsBeneathDirectory() throws Exception {
-    runTestPackageLoadingError(/*keepGoing=*/ false, "//bad/...");
+    runTestPackageLoadingError(/* keepGoing= */ false, "//bad/...");
   }
 
   @Test
@@ -1800,7 +1800,7 @@
 
     private final MockToolsConfig mockToolsConfig;
 
-    LoadingPhaseTester() throws IOException, OptionsParsingException {
+    LoadingPhaseTester() throws IOException, OptionsParsingException, AbruptExitException {
       this.workspace = fs.getPath("/workspace");
       workspace.createDirectory();
       mockToolsConfig = new MockToolsConfig(workspace);
@@ -1911,19 +1911,19 @@
     }
 
     public TargetPatternPhaseValue load(String... patterns) throws Exception {
-      return loadWithFlags(/*keepGoing=*/ false, /*determineTests=*/ false, patterns);
+      return loadWithFlags(/* keepGoing= */ false, /* determineTests= */ false, patterns);
     }
 
     TargetPatternPhaseValue loadKeepGoing(String... patterns) throws Exception {
-      return loadWithFlags(/*keepGoing=*/ true, /*determineTests=*/ false, patterns);
+      return loadWithFlags(/* keepGoing= */ true, /* determineTests= */ false, patterns);
     }
 
     TargetPatternPhaseValue loadTests(String... patterns) throws Exception {
-      return loadWithFlags(/*keepGoing=*/ false, /*determineTests=*/ true, patterns);
+      return loadWithFlags(/* keepGoing= */ false, /* determineTests= */ true, patterns);
     }
 
     TargetPatternPhaseValue loadTestsKeepGoing(String... patterns) throws Exception {
-      return loadWithFlags(/*keepGoing=*/ true, /*determineTests=*/ true, patterns);
+      return loadWithFlags(/* keepGoing= */ true, /* determineTests= */ true, patterns);
     }
 
     TargetPatternPhaseValue loadWithFlags(
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/PackageLoadingTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/PackageLoadingTest.java
index 4e29d5c..08adc15 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/PackageLoadingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/PackageLoadingTest.java
@@ -125,7 +125,7 @@
   }
 
   private void setUpSkyframe(
-      PackageOptions packageOptions, BuildLanguageOptions buildLanguageOptions) {
+      PackageOptions packageOptions, BuildLanguageOptions buildLanguageOptions) throws Exception {
     PathPackageLocator pkgLocator =
         PathPackageLocator.create(
             /* outputBase= */ null,
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/PathPackageLocatorTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/PathPackageLocatorTest.java
index d05e7b6..8ce491f 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/PathPackageLocatorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/PathPackageLocatorTest.java
@@ -14,26 +14,26 @@
 package com.google.devtools.build.lib.pkgcache;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.server.FailureDetails.PackageOptions.Code;
 import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
+import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.Root;
 import com.google.devtools.build.lib.vfs.SyscallCache;
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/**
- * Test package-path logic.
- */
+/** Test package-path logic. */
 @RunWith(JUnit4.class)
 public class PathPackageLocatorTest extends FoundationTestCase {
   private Path buildBazelFile1A;
@@ -103,7 +103,7 @@
     rootDir2 = scratch.resolve("/somewhere/1234567/build/workspace");
     rootDir3ParentParent = scratch.resolve("/usr/local/google/jrluser-foo");
     rootDir3 = rootDir3ParentParent.getRelative("READONLY/workspace");
-    rootDir4Parent =  scratch.resolve("/usr/local/symlinks/client_symlink_jrluser-foo");
+    rootDir4Parent = scratch.resolve("/usr/local/symlinks/client_symlink_jrluser-foo");
     rootDir4 = rootDir4Parent.getRelative("workspace");
     rootDir5 = scratch.resolve("/foo/bar");
 
@@ -134,8 +134,7 @@
     buildFile3CI = rootDir3.getRelative("C/I/BUILD");
 
     // Root4
-    FileSystemUtils.ensureSymbolicLink(
-        rootDir4.getRelative("A"), rootDir1.getRelative("A"));
+    FileSystemUtils.ensureSymbolicLink(rootDir4.getRelative("A"), rootDir1.getRelative("A"));
     FileSystemUtils.ensureSymbolicLink(
         rootDir4.getRelative("B/BUILD"), rootDir1.getRelative("B/BUILD"));
     FileSystemUtils.ensureSymbolicLink(
@@ -146,8 +145,7 @@
         rootDir4.getRelative("C/E/BUILD"), rootDir1.getRelative("C/E/BUILD"));
     FileSystemUtils.ensureSymbolicLink(
         rootDir4.getRelative("F/G/BUILD"), rootDir1.getRelative("F/G/BUILD"));
-    FileSystemUtils.ensureSymbolicLink(
-        rootDir4.getRelative("H/I"), rootDir5.getRelative("H/I"));
+    FileSystemUtils.ensureSymbolicLink(rootDir4.getRelative("H/I"), rootDir5.getRelative("H/I"));
 
     // Root5
     createBuildFile(rootDir5, "H/I");
@@ -266,23 +264,23 @@
     assertThat(locator.getWorkspaceFile(SyscallCache.NO_CACHE)).isEqualTo(rootDir1WorkspaceFile);
   }
 
-  private Path setLocator(String root) {
-    Path nonExistentRoot = scratch.resolve(root);
+  private void setLocator(String... roots) throws Exception {
     this.locator =
         PathPackageLocator.create(
-            /*outputBase=*/ null,
-            Arrays.asList(root),
+            /* outputBase= */ null,
+            Arrays.asList(roots),
             reporter,
-            /*workspace=*/ FileSystemUtils.getWorkingDirectory(),
+            /* workspace= */ FileSystemUtils.getWorkingDirectory(),
             /* clientWorkingDirectory= */ FileSystemUtils.getWorkingDirectory(
                 scratch.getFileSystem()),
             BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
-    return nonExistentRoot;
   }
 
   @Test
   public void nonexistentRoot() throws Exception {
-    Path nonExistentRoot1 = setLocator("/non/existent/1/workspace");
+    scratch.dir("/existing/root");
+    Path nonExistentRoot1 = scratch.resolve("/non/existent/1/workspace");
+    setLocator("/existing/root", nonExistentRoot1.getPathString());
     createBuildFile(nonExistentRoot1, "X");
     // Now let's create the root:
     // The package isn't found
@@ -297,15 +295,16 @@
     Path belowClient = clientPath.getRelative("below/client");
     scratch.dir(belowClient.getPathString());
 
-    List<String> pathElements = ImmutableList.of(
-        "./below/client",        // Client-relative
-        ".",                     // Client-relative
-        "%workspace%/somewhere", // Workspace-relative
-        // Absolute
-        clientPath.getRelative("below").getPathString());
+    ImmutableList<String> pathElements =
+        ImmutableList.of(
+            "./below/client", // Client-relative
+            ".", // Client-relative
+            "%workspace%/somewhere", // Workspace-relative
+            // Absolute
+            clientPath.getRelative("below").getPathString());
     assertThat(
             PathPackageLocator.create(
-                    /*outputBase=*/ null,
+                    /* outputBase= */ null,
                     pathElements,
                     reporter,
                     workspace.asFragment(),
@@ -323,10 +322,12 @@
   @Test
   public void testRelativePathWarning() throws Exception {
     Path workspace = scratch.dir("/some/path/to/workspace");
+    scratch.dir("/some/path/to/workspace/foo");
+    scratch.dir("/some/path/to/workspace/foo/foo");
 
     // No warning if workspace == cwd.
     PathPackageLocator.create(
-        /*outputBase=*/ null,
+        /* outputBase= */ null,
         ImmutableList.of("./foo"),
         reporter,
         workspace.asFragment(),
@@ -335,7 +336,7 @@
     assertThat(eventCollector.count()).isSameInstanceAs(0);
 
     PathPackageLocator.create(
-        /*outputBase=*/ null,
+        /* outputBase= */ null,
         ImmutableList.of("./foo"),
         reporter,
         workspace.asFragment(),
@@ -349,13 +350,36 @@
   @Test
   public void testDollarSigns() throws Exception {
     Path workspace = scratch.dir("/some/path/to/workspace$1");
+    scratch.dir("/some/path/to/workspace$1/blabla");
 
     PathPackageLocator.create(
-        /*outputBase=*/ null,
+        /* outputBase= */ null,
         ImmutableList.of("%workspace%/blabla"),
         reporter,
         workspace.asFragment(),
         workspace.getRelative("foo"),
         BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
   }
+
+  @Test
+  public void testNonExistentPackagePath() throws Exception {
+    Path workspace = scratch.dir("/some/path/to/workspace");
+    AbruptExitException e =
+        assertThrows(
+            AbruptExitException.class,
+            () ->
+                PathPackageLocator.create(
+                    /* outputBase= */ null,
+                    ImmutableList.of("/nonexistent1", "/nonexistent2"),
+                    reporter,
+                    workspace.asFragment(),
+                    workspace,
+                    BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY));
+    assertThat(e.getDetailedExitCode().getFailureDetail().getMessage())
+        .contains(
+            "None of the directories specified in --package_path '/nonexistent1:/nonexistent2'"
+                + " exist");
+    assertThat(e.getDetailedExitCode().getFailureDetail().getPackageOptions().getCode())
+        .isEqualTo(Code.PACKAGE_PATH_INVALID);
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java b/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
index 1a3255e..590c947 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
@@ -337,20 +337,21 @@
     buildLanguageOptions.setExperimentalDormantDeps(true);
 
     ImmutableList<BuildFileName> buildFilesByPriority = skyframeExecutor.getBuildFilesByPriority();
-    PathPackageLocator packageLocator =
-        useVirtualSourceRoot()
-            ? PathPackageLocator.createWithoutExistenceCheck(
-                /* outputBase= */ null,
-                ImmutableList.of(directories.getVirtualSourceRoot()),
-                buildFilesByPriority)
-            : PathPackageLocator.create(
-                directories.getOutputBase(),
-                packageOptions.getPackagePath(),
-                getReporter(),
-                directories.getWorkspace().asFragment(),
-                rootDirectory,
-                buildFilesByPriority);
+    PathPackageLocator packageLocator;
     try {
+      packageLocator =
+          useVirtualSourceRoot()
+              ? PathPackageLocator.createWithoutExistenceCheck(
+                  /* outputBase= */ null,
+                  ImmutableList.of(directories.getVirtualSourceRoot()),
+                  buildFilesByPriority)
+              : PathPackageLocator.create(
+                  directories.getOutputBase(),
+                  packageOptions.getPackagePath(),
+                  getReporter(),
+                  directories.getWorkspace().asFragment(),
+                  rootDirectory,
+                  buildFilesByPriority);
       skyframeExecutor.sync(
           getReporter(),
           packageLocator,