diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 2078abc029e6f3b79bd3980ea5c6d16b314a3c28..86be517bf03b8b740ebd9d903e4e839fc08474ff 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -240,6 +240,20 @@ class OC_Mount_Config {
 		}
 		foreach ($options as &$option) {
 			$option = self::substitutePlaceholdersInConfig($option);
+			if(!self::arePlaceholdersSubstituted($option)) {
+				\OC::$server->getLogger()->error(
+					'A placeholder was not substituted: {option} for mount type {class}',
+					[
+						'app' => 'files_external',
+						'option' => $option,
+						'class' => $class,
+					]
+				);
+				throw new StorageNotAvailableException(
+					'Mount configuration incomplete',
+					StorageNotAvailableException::STATUS_INCOMPLETE_CONF
+				);
+			}
 		}
 		if (class_exists($class)) {
 			try {
@@ -264,6 +278,22 @@ class OC_Mount_Config {
 		return StorageNotAvailableException::STATUS_ERROR;
 	}
 
+	public static function arePlaceholdersSubstituted($option):bool {
+		$result = true;
+		if(is_array($option)) {
+			foreach ($option as $optionItem) {
+				if(is_array($optionItem)) {
+					$result = $result && self::arePlaceholdersSubstituted($option);
+				}
+			}
+		} else if (is_string($option)) {
+			if (strpos($option, '$') !== false) {
+				$result = false;
+			}
+		}
+		return $result;
+	}
+
 	/**
 	 * Read the mount points in the config file into an array
 	 *