diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp
index 2a291f7c0..218259aa8 100644
--- a/lib/CModHandler.cpp
+++ b/lib/CModHandler.cpp
@@ -551,6 +551,12 @@ static JsonNode loadModSettings(std::string path)
 	return JsonNode();
 }
 
+JsonNode addMeta(JsonNode config, std::string meta)
+{
+	config.setMeta(meta);
+	return std::move(config);
+}
+
 CModInfo::CModInfo(std::string identifier,const JsonNode & local, const JsonNode & config):
 	identifier(identifier),
 	name(config["name"].String()),
@@ -558,7 +564,7 @@ CModInfo::CModInfo(std::string identifier,const JsonNode & local, const JsonNode
 	dependencies(config["depends"].convertTo<std::set<std::string> >()),
 	conflicts(config["conflicts"].convertTo<std::set<std::string> >()),
 	validation(PENDING),
-	config(config)
+	config(addMeta(config, identifier))
 {
 	loadLocalData(local);
 }
@@ -577,6 +583,7 @@ JsonNode CModInfo::saveLocalData()
 
 void CModInfo::updateChecksum(ui32 newChecksum)
 {
+	// comment-out next line to force validation of all mods ignoring checksum
 	if (newChecksum != checksum)
 	{
 		checksum = newChecksum;
diff --git a/lib/JsonDetail.cpp b/lib/JsonDetail.cpp
index 94932861f..0baec2745 100644
--- a/lib/JsonDetail.cpp
+++ b/lib/JsonDetail.cpp
@@ -11,7 +11,10 @@
 #include "StdInc.h"
 #include "JsonDetail.h"
 
+#include "VCMI_Lib.h"
 #include "CGeneralTextHandler.h"
+#include "CModHandler.h"
+
 #include "filesystem/Filesystem.h"
 #include "ScopeGuard.h"
 
@@ -879,52 +882,71 @@ namespace
 
 	namespace Formats
 	{
-		#define TEST_FILE(prefix, file, type) \
-			if (CResourceHandler::get()->existsResource(ResourceID(prefix + file, type))) \
+		bool testFilePresence(std::string scope, ResourceID resource)
+		{
+			std::set<std::string> allowedScopes;
+			if (scope != "core" && scope != "") // all real mods may have dependencies
+			{
+				//NOTE: recursive dependencies are not allowed at the moment - update code if this changes
+				allowedScopes = VLC->modh->getModData(scope).dependencies;
+				allowedScopes.insert("core"); // all mods can use H3 files
+			}
+			allowedScopes.insert(scope); // mods can use their own files
+
+			for (auto & entry : allowedScopes)
+			{
+				if (CResourceHandler::get(entry)->existsResource(resource))
+					return true;
+			}
+			return false;
+		}
+
+		#define TEST_FILE(scope, prefix, file, type) \
+			if (testFilePresence(scope, ResourceID(prefix + file, type))) \
 				return ""
 
-		std::string testAnimation(std::string path)
+		std::string testAnimation(std::string path, std::string scope)
 		{
-			TEST_FILE("Sprites/", path, EResType::ANIMATION);
-			TEST_FILE("Sprites/", path, EResType::TEXT);
+			TEST_FILE(scope, "Sprites/", path, EResType::ANIMATION);
+			TEST_FILE(scope, "Sprites/", path, EResType::TEXT);
 			return "Animation file \"" + path + "\" was not found";
 		}
 
 		std::string textFile(const JsonNode & node)
 		{
-			TEST_FILE("", node.String(), EResType::TEXT);
+			TEST_FILE(node.meta, "", node.String(), EResType::TEXT);
 			return "Text file \"" + node.String() + "\" was not found";
 		}
 
 		std::string musicFile(const JsonNode & node)
 		{
-			TEST_FILE("", node.String(), EResType::MUSIC);
+			TEST_FILE(node.meta, "", node.String(), EResType::MUSIC);
 			return "Music file \"" + node.String() + "\" was not found";
 		}
 
 		std::string soundFile(const JsonNode & node)
 		{
-			TEST_FILE("Sounds/", node.String(), EResType::SOUND);
+			TEST_FILE(node.meta, "Sounds/", node.String(), EResType::SOUND);
 			return "Sound file \"" + node.String() + "\" was not found";
 		}
 
 		std::string defFile(const JsonNode & node)
 		{
-			TEST_FILE("Sprites/", node.String(), EResType::ANIMATION);
+			TEST_FILE(node.meta, "Sprites/", node.String(), EResType::ANIMATION);
 			return "Def file \"" + node.String() + "\" was not found";
 		}
 
 		std::string animationFile(const JsonNode & node)
 		{
-			return testAnimation(node.String());
+			return testAnimation(node.String(), node.meta);
 		}
 
 		std::string imageFile(const JsonNode & node)
 		{
-			TEST_FILE("Data/", node.String(), EResType::IMAGE);
-			TEST_FILE("Sprites/", node.String(), EResType::IMAGE);
+			TEST_FILE(node.meta, "Data/", node.String(), EResType::IMAGE);
+			TEST_FILE(node.meta, "Sprites/", node.String(), EResType::IMAGE);
 			if (node.String().find(':') != std::string::npos)
-				return testAnimation(node.String().substr(0, node.String().find(':')));
+				return testAnimation(node.String().substr(0, node.String().find(':')), node.meta);
 			return "Image file \"" + node.String() + "\" was not found";
 		}
 
diff --git a/lib/filesystem/Filesystem.cpp b/lib/filesystem/Filesystem.cpp
index 4236e30a4..78ed3966e 100644
--- a/lib/filesystem/Filesystem.cpp
+++ b/lib/filesystem/Filesystem.cpp
@@ -153,8 +153,7 @@ void CResourceHandler::initialize()
 
 ISimpleResourceLoader * CResourceHandler::get()
 {
-	assert(resourceLoader);
-	return resourceLoader;
+	return get("");
 }
 
 ISimpleResourceLoader * CResourceHandler::get(std::string identifier)
@@ -175,6 +174,7 @@ void CResourceHandler::load(const std::string &fsConfigURI)
 	const JsonNode fsConfig((char*)fsConfigData.first.get(), fsConfigData.second);
 
 	resourceLoader = new CFilesystemList();
+	knownLoaders[""] = resourceLoader;
 	addFilesystem("core", createFileSystem("", fsConfig["filesystem"]));
 
 	// hardcoded system-specific path, may not be inside any of data directories
@@ -184,6 +184,7 @@ void CResourceHandler::load(const std::string &fsConfigURI)
 
 void CResourceHandler::addFilesystem(const std::string & identifier, ISimpleResourceLoader * loader)
 {
+	assert(knownLoaders.count(identifier) == 0);
 	resourceLoader->addLoader(loader, false);
 	knownLoaders[identifier] = loader;
 }