diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 2c709d31b..18ee3a521 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -880,6 +880,21 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
 	return 0;
 }
 
+static void checkArea(v3s16 &minp, v3s16 &maxp)
+{
+	auto volume = VoxelArea(minp, maxp).getVolume();
+	// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+	if (volume > 4096000) {
+		throw LuaError("Area volume exceeds allowed value of 4096000");
+	}
+
+	// Clamp to map range to avoid problems
+#define CLAMP(arg) core::clamp(arg, (s16)-MAX_MAP_GENERATION_LIMIT, (s16)MAX_MAP_GENERATION_LIMIT)
+	minp = v3s16(CLAMP(minp.X), CLAMP(minp.Y), CLAMP(minp.Z));
+	maxp = v3s16(CLAMP(maxp.X), CLAMP(maxp.Y), CLAMP(maxp.Z));
+#undef CLAMP
+}
+
 // find_nodes_in_area(minp, maxp, nodenames, [grouped])
 int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
 {
@@ -899,13 +914,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
 	}
 #endif
 
-	v3s16 cube = maxp - minp + 1;
-	// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
-	if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
-		luaL_error(L, "find_nodes_in_area(): area volume"
-				" exceeds allowed value of 4096000");
-		return 0;
-	}
+	checkArea(minp, maxp);
 
 	std::vector<content_t> filter;
 	collectNodeIds(L, 3, ndef, filter);
@@ -1010,13 +1019,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
 	}
 #endif
 
-	v3s16 cube = maxp - minp + 1;
-	// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
-	if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
-		luaL_error(L, "find_nodes_in_area_under_air(): area volume"
-				" exceeds allowed value of 4096000");
-		return 0;
-	}
+	checkArea(minp, maxp);
 
 	std::vector<content_t> filter;
 	collectNodeIds(L, 3, ndef, filter);
diff --git a/src/unittest/test_voxelarea.cpp b/src/unittest/test_voxelarea.cpp
index 6ec0412d5..9826d2ee7 100644
--- a/src/unittest/test_voxelarea.cpp
+++ b/src/unittest/test_voxelarea.cpp
@@ -30,6 +30,7 @@ public:
 
 	void test_addarea();
 	void test_pad();
+	void test_extent();
 	void test_volume();
 	void test_contains_voxelarea();
 	void test_contains_point();
@@ -65,6 +66,7 @@ void TestVoxelArea::runTests(IGameDef *gamedef)
 {
 	TEST(test_addarea);
 	TEST(test_pad);
+	TEST(test_extent);
 	TEST(test_volume);
 	TEST(test_contains_voxelarea);
 	TEST(test_contains_point);
@@ -113,10 +115,22 @@ void TestVoxelArea::test_pad()
 	UASSERT(v1.MaxEdge == v3s16(-47, -9347, 969));
 }
 
+void TestVoxelArea::test_extent()
+{
+	VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669));
+	UASSERT(v1.getExtent() == v3s16(1191, 995, 1459));
+
+	VoxelArea v2(v3s16(32493, -32507, 32753), v3s16(32508, -32492, 32768));
+	UASSERT(v2.getExtent() == v3s16(16, 16, 16));
+}
+
 void TestVoxelArea::test_volume()
 {
-	VoxelArea v1(v3s16(-1337, 447, -789), v3s16(-147, -9547, 669));
-	UASSERTEQ(s32, v1.getVolume(), -184657133);
+	VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669));
+	UASSERTEQ(s32, v1.getVolume(), 1728980655);
+
+	VoxelArea v2(v3s16(32493, -32507, 32753), v3s16(32508, -32492, 32768));
+	UASSERTEQ(s32, v2.getVolume(), 4096);
 }
 
 void TestVoxelArea::test_contains_voxelarea()