diff --git a/src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java b/src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java
index 3a2769cf467ee9..8751d5b2997184 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java
@@ -47,6 +47,7 @@
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
+import com.google.devtools.build.lib.remote.common.CacheNotFoundException;
 import com.google.devtools.build.lib.remote.util.AsyncTaskCache;
 import com.google.devtools.build.lib.util.TempPathGenerator;
 import com.google.devtools.build.lib.vfs.FileSymlinkLoopException;
@@ -394,14 +395,24 @@ private ListenableFuture<Void> prefetchFile(
 
       Completable result =
           downloadFileNoCheckRx(
-              action,
-              execRoot.getRelative(execPath),
-              treeRootExecPath != null ? execRoot.getRelative(treeRootExecPath) : null,
-              dirsWithOutputPermissions,
-              input,
-              metadata,
-              priority,
-              reason);
+                  action,
+                  execRoot.getRelative(execPath),
+                  treeRootExecPath != null ? execRoot.getRelative(treeRootExecPath) : null,
+                  dirsWithOutputPermissions,
+                  input,
+                  metadata,
+                  priority,
+                  reason)
+              .onErrorResumeNext(
+                  t -> {
+                    if (t instanceof CacheNotFoundException cacheNotFoundException) {
+                      // Only the symlink itself is guaranteed to be an input to the action, so
+                      // report its path for rewinding.
+                      cacheNotFoundException.setExecPath(input.getExecPath());
+                      return Completable.error(cacheNotFoundException);
+                    }
+                    return Completable.error(t);
+                  });
 
       if (symlink != null) {
         result = result.andThen(plantSymlink(symlink));
diff --git a/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java
index 423546c301f85a..55f08a12644024 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java
@@ -418,6 +418,127 @@ public void remoteCacheEvictBlobs_whenPrefetchingInput_succeedsWithActionRewindi
     assertValidOutputFile("a/bar.out", "foo" + lineSeparator() + "updated bar" + lineSeparator());
   }
 
+  @Test
+  public void remoteCacheEvictBlobs_whenPrefetchingSymlinkedInput_exitWithCode39()
+      throws Exception {
+    // Arrange: Prepare workspace and populate remote cache
+    writeSymlinkRule();
+    write(
+        "a/BUILD",
+        """
+        load("//:symlink.bzl", "symlink")
+
+        genrule(
+            name = "foo",
+            srcs = ["foo.in"],
+            outs = ["foo.out"],
+            cmd = "cat $(SRCS) > $@",
+        )
+
+        symlink(
+            name = "symlinked_foo",
+            target_artifact = ":foo.out",
+        )
+
+        genrule(
+            name = "bar",
+            srcs = [
+                ":symlinked_foo",
+                "bar.in",
+            ],
+            outs = ["bar.out"],
+            cmd = "cat $(SRCS) > $@",
+            tags = ["no-remote-exec"],
+        )
+        """);
+    write("a/foo.in", "foo");
+    write("a/bar.in", "bar");
+
+    // Populate remote cache
+    buildTarget("//a:bar");
+    var bytes = readContent(getOutputPath("a/foo.out"));
+    var hashCode = getDigestHashFunction().getHashFunction().hashBytes(bytes);
+    getOnlyElement(getArtifacts("//a:symlinked_foo")).getPath().delete();
+    getOutputPath("a/foo.out").delete();
+    getOutputPath("a/bar.out").delete();
+    getOutputBase().getRelative("action_cache").deleteTreesBelow();
+    restartServer();
+
+    // Clean build, foo.out isn't downloaded
+    buildTarget("//a:bar");
+    assertOutputDoesNotExist("a/foo.out");
+    assertOutputsDoNotExist("//a:symlinked_foo");
+
+    // Act: Evict blobs from remote cache and do an incremental build
+    evictAllBlobs();
+    write("a/bar.in", "updated bar");
+    var error = assertThrows(BuildFailedException.class, () -> buildTarget("//a:bar"));
+
+    // Assert: Exit code is 39
+    assertThat(error).hasMessageThat().contains("Lost inputs no longer available remotely");
+    assertThat(error).hasMessageThat().contains("a/symlinked_foo");
+    assertThat(error).hasMessageThat().contains(String.format("%s/%s", hashCode, bytes.length));
+    assertThat(error.getDetailedExitCode().getExitCode().getNumericExitCode()).isEqualTo(39);
+  }
+
+  @Test
+  public void remoteCacheEvictBlobs_whenPrefetchingSymlinkedInput_succeedsWithActionRewinding()
+      throws Exception {
+    writeSymlinkRule();
+    write(
+        "a/BUILD",
+        """
+        load("//:symlink.bzl", "symlink")
+
+        genrule(
+            name = "foo",
+            srcs = ["foo.in"],
+            outs = ["foo.out"],
+            cmd = "cat $(SRCS) > $@",
+        )
+
+        symlink(
+            name = "symlinked_foo",
+            target_artifact = ":foo.out",
+        )
+
+        genrule(
+            name = "bar",
+            srcs = [
+                ":symlinked_foo",
+                "bar.in",
+            ],
+            outs = ["bar.out"],
+            cmd = "cat $(SRCS) > $@",
+            tags = ["no-remote-exec"],
+        )
+        """);
+    write("a/foo.in", "foo");
+    write("a/bar.in", "bar");
+
+    // Populate remote cache
+    buildTarget("//a:bar");
+    getOnlyElement(getArtifacts("//a:symlinked_foo")).getPath().delete();
+    getOutputPath("a/foo.out").delete();
+    getOutputPath("a/bar.out").delete();
+    getOutputBase().getRelative("action_cache").deleteTreesBelow();
+    restartServer();
+
+    // Clean build, foo.out isn't downloaded
+    buildTarget("//a:bar");
+    assertOutputDoesNotExist("a/foo.out");
+    assertOutputsDoNotExist("//a:symlinked_foo");
+
+    // Act: Evict blobs from remote cache and do an incremental build
+    evictAllBlobs();
+    write("a/bar.in", "updated bar");
+    enableActionRewinding();
+    buildTarget("//a:bar");
+
+    // Assert: target was successfully built
+    assertValidOutputFile("a/bar.out", "foo" + lineSeparator() + "updated bar" + lineSeparator());
+  }
+
   @Test
   public void remoteCacheEvictBlobs_whenUploadingInput_exitWithCode39() throws Exception {
     // Arrange: Prepare workspace and populate remote cache
diff --git a/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTestBase.java b/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTestBase.java
index b53b8f82770efd..2a9041c94023be 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTestBase.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTestBase.java
@@ -37,6 +37,7 @@
 import com.google.devtools.build.lib.util.CommandBuilder;
 import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.io.RecordingOutErr;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.io.IOException;
@@ -2033,6 +2034,7 @@ protected void assertSymlink(String binRelativeLinkPath, PathFragment targetPath
   }
 
   protected void writeSymlinkRule() throws IOException {
+    FileSystemUtils.touchFile(getWorkspace().getRelative("BUILD"));
     write(
         "symlink.bzl",
         """