diff --git a/CHANGELOG.md b/CHANGELOG.md
index 499190aeb855837c6029f87e125731d2bd8632b7..6898772f8d7299037aa4806c036e9a0839e74ae3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
 
 All notable changes to this project will be documented in this file.
 
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
@@ -33,6 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - NaN Double Values (see #41)
 
+- #14 - Handle files on file system without File entity: Those entries are
+  returned without ID but with a notice now.
+
 ### Security (in case of vulnerabilities)
 
 - TLS is by default restricted to v1.2 and v1.3 now.
diff --git a/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java b/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java
index 8e0afcbdc50985f1fa1a939940c05f8429562c90..6366bd2884aca38a0d54eca4a926fcc7e8b9cda4 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/GetFileRecordByPath.java
@@ -27,6 +27,7 @@ package caosdb.server.database.backend.transaction;
 import caosdb.server.caching.Cache;
 import caosdb.server.database.CacheableBackendTransaction;
 import caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl;
+import caosdb.server.database.exceptions.EntityDoesNotExistException;
 import caosdb.server.database.exceptions.TransactionException;
 import caosdb.server.database.proto.SparseEntity;
 import org.apache.commons.jcs.access.behavior.ICacheAccess;
@@ -62,7 +63,11 @@ public class GetFileRecordByPath extends CacheableBackendTransaction<String, Spa
   @Override
   public SparseEntity executeNoCache() throws TransactionException {
     final GetFileRecordByPathImpl t = getImplementation(GetFileRecordByPathImpl.class);
-    return t.execute(getKey());
+    SparseEntity result = t.execute(getKey());
+    if (result == null) {
+      throw new EntityDoesNotExistException();
+    }
+    return result;
   }
 
   public Integer getId() {
diff --git a/src/main/java/caosdb/server/entity/Message.java b/src/main/java/caosdb/server/entity/Message.java
index 03e788251620b6c192eb86f1bbd172564a66235f..0ffedb4316fe372e09f3b69ca5824a72f98accaf 100644
--- a/src/main/java/caosdb/server/entity/Message.java
+++ b/src/main/java/caosdb/server/entity/Message.java
@@ -79,8 +79,8 @@ public class Message extends Exception implements Comparable<Message>, ToElement
     this(type, code, null, null);
   }
 
-  public Message(final Integer code, final String description) {
-    this("Message", code, description, null);
+  public Message(Integer code, String description) {
+    this(MessageType.Info, code, description);
   }
 
   public Message(final MessageType type, final Integer code, final String description) {
@@ -96,6 +96,10 @@ public class Message extends Exception implements Comparable<Message>, ToElement
     this(type, code, description, null);
   }
 
+  public Message(MessageType type, String description) {
+    this(type.toString(), 0, description);
+  }
+
   public Message(
       final String type, final Integer code, final String description, final String body) {
     this.code = code;
diff --git a/src/main/java/caosdb/server/resource/FileSystemResource.java b/src/main/java/caosdb/server/resource/FileSystemResource.java
index 290a88801b4f14401981f9d91a6ba00cf27c12a4..37f0e9ffda3f81b84c6001c5521ba5c8451b473e 100644
--- a/src/main/java/caosdb/server/resource/FileSystemResource.java
+++ b/src/main/java/caosdb/server/resource/FileSystemResource.java
@@ -26,9 +26,12 @@ import static caosdb.server.FileSystem.getFromFileSystem;
 import static java.net.URLDecoder.decode;
 
 import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.database.exceptions.EntityDoesNotExistException;
 import caosdb.server.database.misc.TransactionBenchmark;
 import caosdb.server.entity.Entity;
 import caosdb.server.entity.FileProperties;
+import caosdb.server.entity.Message;
+import caosdb.server.entity.Message.MessageType;
 import caosdb.server.entity.RetrieveEntity;
 import caosdb.server.entity.container.TransactionContainer;
 import caosdb.server.permissions.EntityPermission;
@@ -56,6 +59,11 @@ import org.restlet.representation.Representation;
  */
 public class FileSystemResource extends AbstractCaosDBServerResource {
 
+  public static Message ORPHANED_FILE_WARNING =
+      new Message(
+          MessageType.Warning,
+          "Orphaned file. The file is not tracked. This is probably a harmless inconsistency but it might be a sign of other problems.");
+
   /**
    * Download a File from the CaosDBFileSystem. Only one File per Request.
    *
@@ -124,6 +132,13 @@ public class FileSystemResource extends AbstractCaosDBServerResource {
 
     } else {
 
+      try {
+        getEntity(specifier).checkPermission(EntityPermission.RETRIEVE_FILE);
+      } catch (EntityDoesNotExistException exception) {
+        // This file in the file system has no corresponding File record.
+        return error(ServerMessages.NOT_PERMITTED, Status.CLIENT_ERROR_FORBIDDEN);
+      }
+
       final MediaType mt = MediaType.valueOf(FileUtils.getMimeType(file));
       final FileRepresentation ret = new FileRepresentation(file, mt);
       ret.setDisposition(new Disposition(Disposition.TYPE_ATTACHMENT));
@@ -149,19 +164,39 @@ public class FileSystemResource extends AbstractCaosDBServerResource {
     return null;
   }
 
+  /**
+   * Return an element for the given file on a file system.
+   *
+   * <p>If there is no File entity for this file, an element without `id` is returned, instead a
+   * corresponding message is added to the element.
+   */
   Element getFileElement(final String directory, final File file) throws Exception {
     final Element celem = new Element("file");
-    celem.setAttribute(
-        "id",
-        getEntityID((directory.endsWith("/") ? directory : directory + "/") + file.getName()));
     celem.setAttribute("name", file.getName());
+
+    try {
+      final String entId =
+          getEntityID((directory.endsWith("/") ? directory : directory + "/") + file.getName());
+      celem.setAttribute("id", entId);
+    } catch (EntityDoesNotExistException exception) {
+      // This file in the file system has no corresponding File record.
+      ORPHANED_FILE_WARNING.addToElement(celem);
+    }
     return celem;
   }
 
   protected String getEntityID(final String path) throws Exception {
-    return getEntity(path).getId().toString();
+    final Entity fileEnt = getEntity(path);
+    return fileEnt.getId().toString();
   }
 
+  /**
+   * Throws EntityDoesNotExistException when there is not entity with that path.
+   *
+   * @param path
+   * @return
+   * @throws Exception
+   */
   private Entity getEntity(final String path) throws Exception {
     final long t1 = System.currentTimeMillis();
     final TransactionContainer c = new TransactionContainer();
@@ -178,19 +213,9 @@ public class FileSystemResource extends AbstractCaosDBServerResource {
 
   protected File getFile(final String path) throws Exception {
     final File ret = getFromFileSystem(path);
-    if (ret != null && ret.isFile()) {
-      checkPermissions(path);
-    }
     return ret;
   }
 
-  private final void checkPermissions(final String path) throws Exception {
-    final long t1 = System.currentTimeMillis();
-    getEntity(path).checkPermission(EntityPermission.RETRIEVE_FILE);
-    final long t2 = System.currentTimeMillis();
-    getBenchmark().addMeasurement(this.getClass().getSimpleName() + ".checkPermissions", t2 - t1);
-  }
-
   @Override
   protected Representation httpPostInChildClass(final Representation entity)
       throws ConnectionException, JDOMException {