diff --git a/armory/Sources/armory/logicnode/ReadFileNode.hx b/armory/Sources/armory/logicnode/ReadFileNode.hx
index e8d4f9639..0a50611cf 100644
--- a/armory/Sources/armory/logicnode/ReadFileNode.hx
+++ b/armory/Sources/armory/logicnode/ReadFileNode.hx
@@ -22,6 +22,8 @@ class ReadFileNode extends LogicNode {
 			if (!useCache) iron.data.Data.cachedBlobs.remove(file);
 			runOutput(0);
 		});
+
+		if (data == null) runOutput(1);
 	}
 
 	override function get(from: Int): Dynamic {
diff --git a/armory/Sources/armory/logicnode/ReadJsonNode.hx b/armory/Sources/armory/logicnode/ReadJsonNode.hx
index 1c7c06dea..22775b994 100644
--- a/armory/Sources/armory/logicnode/ReadJsonNode.hx
+++ b/armory/Sources/armory/logicnode/ReadJsonNode.hx
@@ -22,6 +22,8 @@ class ReadJsonNode extends LogicNode {
 			if (!useCache) iron.data.Data.cachedBlobs.remove(file);
 			runOutput(0);
 		});
+
+		if (data == null) runOutput(1);
 	}
 
 	override function get(from: Int): Dynamic {
diff --git a/armory/Sources/armory/logicnode/WriteFileNode.hx b/armory/Sources/armory/logicnode/WriteFileNode.hx
index 4e3e8850c..5e911b533 100644
--- a/armory/Sources/armory/logicnode/WriteFileNode.hx
+++ b/armory/Sources/armory/logicnode/WriteFileNode.hx
@@ -25,5 +25,7 @@ class WriteFileNode extends LogicNode {
         a.click();
         js.html.URL.revokeObjectURL(url);
 		#end
+
+		runOutput(0);
 	}
 }
diff --git a/armory/Sources/armory/logicnode/WriteJsonNode.hx b/armory/Sources/armory/logicnode/WriteJsonNode.hx
index cb7160075..eb0a08cf4 100644
--- a/armory/Sources/armory/logicnode/WriteJsonNode.hx
+++ b/armory/Sources/armory/logicnode/WriteJsonNode.hx
@@ -26,5 +26,7 @@ class WriteJsonNode extends LogicNode {
         a.click();
         js.html.URL.revokeObjectURL(url);
 		#end
+
+		runOutput(0);
 	}
 }
diff --git a/armory/blender/arm/logicnode/native/LN_read_file.py b/armory/blender/arm/logicnode/native/LN_read_file.py
index a0fa3091c..9398ae98d 100644
--- a/armory/blender/arm/logicnode/native/LN_read_file.py
+++ b/armory/blender/arm/logicnode/native/LN_read_file.py
@@ -9,8 +9,8 @@ class ReadFileNode(ArmLogicTreeNode):
         time the node is executed. Otherwise, cache the file after the
         first read and return the cached content.
 
-    @output Loaded: activated after the file has been read. If the file
-        doesn't exist, the output is not activated.
+    @output Loaded: activated after the file has been read.
+    @output Not Loaded: If the file doesn't exist the output is activated.
     @output Content: the content of the file.
 
     @seeNode Write File
@@ -18,7 +18,7 @@ class ReadFileNode(ArmLogicTreeNode):
     bl_idname = 'LNReadFileNode'
     bl_label = 'Read File'
     arm_section = 'file'
-    arm_version = 1
+    arm_version = 2
 
     def arm_init(self, context):
         self.add_input('ArmNodeSocketAction', 'In')
@@ -26,4 +26,11 @@ def arm_init(self, context):
         self.add_input('ArmBoolSocket', 'Use cache', default_value=True)
 
         self.add_output('ArmNodeSocketAction', 'Loaded')
+        self.add_output('ArmNodeSocketAction', 'Not loaded')
         self.add_output('ArmStringSocket', 'Content')
+
+    def get_replacement_node(self, node_tree: bpy.types.NodeTree):
+        if self.arm_version not in (0, 1):
+            raise LookupError()
+
+        return NodeReplacement.Identity(self)
diff --git a/armory/blender/arm/logicnode/native/LN_read_json.py b/armory/blender/arm/logicnode/native/LN_read_json.py
index 79a7ad87e..b84f07dd7 100644
--- a/armory/blender/arm/logicnode/native/LN_read_json.py
+++ b/armory/blender/arm/logicnode/native/LN_read_json.py
@@ -9,8 +9,8 @@ class ReadJsonNode(ArmLogicTreeNode):
         time the node is executed. Otherwise, cache the file after the
         first read and return the cached content.
 
-    @output Loaded: activated after the file has been read. If the file
-        doesn't exist, the output is not activated.
+    @output Loaded: activated after the file has been read.
+    @output Not Loaded: If the file doesn't exist the output is activated.
     @output Dynamic: the content of the file.
 
     @seeNode Write JSON
@@ -18,7 +18,7 @@ class ReadJsonNode(ArmLogicTreeNode):
     bl_idname = 'LNReadJsonNode'
     bl_label = 'Read JSON'
     arm_section = 'file'
-    arm_version = 1
+    arm_version = 2
 
     def arm_init(self, context):
         self.add_input('ArmNodeSocketAction', 'In')
@@ -26,4 +26,11 @@ def arm_init(self, context):
         self.add_input('ArmBoolSocket', 'Use cache', default_value=1)
 
         self.add_output('ArmNodeSocketAction', 'Loaded')
+        self.add_output('ArmNodeSocketAction', 'Not loaded')
         self.add_output('ArmDynamicSocket', 'Dynamic')
+
+    def get_replacement_node(self, node_tree: bpy.types.NodeTree):
+        if self.arm_version not in (0, 1):
+            raise LookupError()
+
+        return NodeReplacement.Identity(self)
diff --git a/armory/blender/arm/logicnode/native/LN_write_file.py b/armory/blender/arm/logicnode/native/LN_write_file.py
index d6bbcd900..c713bee25 100644
--- a/armory/blender/arm/logicnode/native/LN_write_file.py
+++ b/armory/blender/arm/logicnode/native/LN_write_file.py
@@ -15,9 +15,17 @@ class WriteFileNode(ArmLogicTreeNode):
     bl_idname = 'LNWriteFileNode'
     bl_label = 'Write File'
     arm_section = 'file'
-    arm_version = 1
+    arm_version = 2
 
     def arm_init(self, context):
         self.add_input('ArmNodeSocketAction', 'In')
         self.add_input('ArmStringSocket', 'File')
         self.add_input('ArmStringSocket', 'Content')
+
+        self.add_output('ArmNodeSocketAction', 'Out')
+
+    def get_replacement_node(self, node_tree: bpy.types.NodeTree):
+        if self.arm_version not in (0, 1):
+            raise LookupError()
+
+        return NodeReplacement.Identity(self)
diff --git a/armory/blender/arm/logicnode/native/LN_write_json.py b/armory/blender/arm/logicnode/native/LN_write_json.py
index 8468b97aa..df98fa029 100644
--- a/armory/blender/arm/logicnode/native/LN_write_json.py
+++ b/armory/blender/arm/logicnode/native/LN_write_json.py
@@ -17,9 +17,17 @@ class WriteJsonNode(ArmLogicTreeNode):
     bl_idname = 'LNWriteJsonNode'
     bl_label = 'Write JSON'
     arm_section = 'file'
-    arm_version = 1
+    arm_version = 2
 
     def arm_init(self, context):
         self.add_input('ArmNodeSocketAction', 'In')
         self.add_input('ArmStringSocket', 'File')
         self.add_input('ArmDynamicSocket', 'Dynamic')
+
+        self.add_output('ArmNodeSocketAction', 'Out')
+
+    def get_replacement_node(self, node_tree: bpy.types.NodeTree):
+        if self.arm_version not in (0, 1):
+            raise LookupError()
+
+        return NodeReplacement.Identity(self)