diff a/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java b/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java
--- a/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java
+++ b/vcs/src/main/java/org/openjdk/skara/vcs/git/GitRepository.java
@@ -627,15 +627,16 @@
         if (entry == null) {
             return Optional.empty();
         }
 
         var parts = entry.split(" ");
-        if (parts[0].equals("160000")) {
+        var mode = parts[0];
+        if (mode.equals("160000")) {
             // submodule
             var hashAndName = parts[2].split("\t");
             return Optional.of(("Subproject commit " + hashAndName[0]).getBytes(StandardCharsets.UTF_8));
-        } else if (parts[0].equals("100644")) {
+        } else if (mode.equals("100644") || mode.equals("100755")) {
             // blob
             var blobAndName = parts[2].split("\t");
             var blob = blobAndName[0];
             try (var p = capture("git", "unpack-file", blob)) {
                 var res = await(p);
diff a/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java b/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java
--- a/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java
+++ b/vcs/src/test/java/org/openjdk/skara/vcs/RepositoryTests.java
@@ -28,10 +28,11 @@
 import org.junit.jupiter.params.provider.EnumSource;
 
 import java.io.IOException;
 import java.net.URI;
 import java.nio.file.*;
+import java.nio.file.attribute.*;
 import java.util.*;
 import java.util.stream.Collectors;
 
 import static java.nio.file.StandardOpenOption.*;
 import static org.junit.jupiter.api.Assertions.*;
@@ -1397,7 +1399,35 @@
 
             Files.write(readme, List.of("Hello, world!"));
             assertTrue(r.isClean());
         }
     }
+
+    @ParameterizedTest
+    @EnumSource(VCS.class)
+    void testShowOnExecutableFiles(VCS vcs) throws IOException {
+        try (var dir = new TemporaryDirectory()) {
+            var r = Repository.init(dir.path(), vcs);
+            assertTrue(r.isClean());
+
+            var readOnlyExecutableFile = dir.path().resolve("hello.sh");
+            Files.write(readOnlyExecutableFile, List.of("echo 'hello'"));
+            if (readOnlyExecutableFile.getFileSystem().supportedFileAttributeViews().contains("posix")) {
+                var permissions = PosixFilePermissions.fromString("r-xr-xr-x");
+                Files.setPosixFilePermissions(readOnlyExecutableFile, permissions);
+            }
+            r.add(readOnlyExecutableFile);
+            var hash = r.commit("Added read only executable file", "duke", "duke@openjdk.java.net");
+            assertEquals(Optional.of(List.of("echo 'hello'")), r.lines(readOnlyExecutableFile, hash));
+
+            var readWriteExecutableFile = dir.path().resolve("goodbye.sh");
+            Files.write(readWriteExecutableFile, List.of("echo 'goodbye'"));
+            if (readOnlyExecutableFile.getFileSystem().supportedFileAttributeViews().contains("posix")) {
+                var permissions = PosixFilePermissions.fromString("rwxrwxrwx");
+                Files.setPosixFilePermissions(readWriteExecutableFile, permissions);
+            }
+            r.add(readWriteExecutableFile);
+            var hash2 = r.commit("Added read-write executable file", "duke", "duke@openjdk.java.net");
+            assertEquals(Optional.of(List.of("echo 'goodbye'")), r.lines(readWriteExecutableFile, hash2));
+        }
+    }
 }
diff a/webrev/src/main/java/org/openjdk/skara/webrev/ModifiedFileView.java b/webrev/src/main/java/org/openjdk/skara/webrev/ModifiedFileView.java
--- a/webrev/src/main/java/org/openjdk/skara/webrev/ModifiedFileView.java
+++ b/webrev/src/main/java/org/openjdk/skara/webrev/ModifiedFileView.java
@@ -41,21 +41,34 @@
         this.patch = patch;
         this.out = out;
         this.navigation = navigation;
         if (patch.isTextual()) {
             binaryContent = null;
-            oldContent = repo.lines(patch.source().path().get(), base).orElseThrow(IllegalArgumentException::new);
+            oldContent = repo.lines(patch.source().path().get(), base).orElseThrow(() -> {
+                throw new IllegalArgumentException("Could not get content for file " +
+                                                   patch.source().path().get() +
+                                                   " at revision " + base);
+            });
             if (head == null) {
                 var path = repo.root().resolve(patch.target().path().get());
                 if (patch.target().type().get().isVCSLink()) {
-                    var content = repo.lines(patch.target().path().get(), repo.head()).orElseThrow(IllegalArgumentException::new);
+                    var tip = repo.head();
+                    var content = repo.lines(patch.target().path().get(), tip).orElseThrow(() -> {
+                        throw new IllegalArgumentException("Could not get content for file " +
+                                                           patch.target().path().get() +
+                                                           " at revision " + tip);
+                    });
                     newContent = List.of(content.get(0) + "-dirty");
                 } else {
                     newContent = Files.readAllLines(path);
                 }
             } else {
-                newContent = repo.lines(patch.target().path().get(), head).orElseThrow(IllegalArgumentException::new);
+                newContent = repo.lines(patch.target().path().get(), head).orElseThrow(() -> {
+                    throw new IllegalArgumentException("Could not get content for file " +
+                                                       patch.target().path().get() +
+                                                       " at revision " + head);
+                });
             }
             stats = new WebrevStats(patch.asTextualPatch().stats(), newContent.size());
         } else {
             oldContent = null;
             newContent = null;
@@ -60,11 +73,15 @@
             oldContent = null;
             newContent = null;
             if (head == null) {
                 binaryContent = Files.readAllBytes(repo.root().resolve(patch.target().path().get()));
             } else {
-                binaryContent = repo.show(patch.target().path().get(), head).orElseThrow(IllegalArgumentException::new);
+                binaryContent = repo.show(patch.target().path().get(), head).orElseThrow(() -> {
+                    throw new IllegalArgumentException("Could not get content for file " +
+                                                       patch.target().path().get() +
+                                                       " at revision " + head);
+                });
             }
             stats = WebrevStats.empty();
         }
     }
 
