diff --git a/arkindex/documents/api/elements.py b/arkindex/documents/api/elements.py
index f08ae65497d605abcdba23bca2c3283615d5ffdd..af312012101898f99fae22be79ff795853334e02 100644
--- a/arkindex/documents/api/elements.py
+++ b/arkindex/documents/api/elements.py
@@ -576,7 +576,7 @@ class ElementsListBase(CorpusACLMixin, DestroyModelMixin, ListAPIView):
         # Retrieve the corpus and check user access rights only once
         corpus_id = self.kwargs.get("corpus")
         if corpus_id is None:
-            return
+            return None
 
         corpus = get_object_or_404(Corpus, id=corpus_id)
         self.check_corpus_access(corpus)
@@ -585,13 +585,13 @@ class ElementsListBase(CorpusACLMixin, DestroyModelMixin, ListAPIView):
     @property
     def folder_filter(self):
         if self.clean_params.get("folder") is None:
-            return
+            return None
         return self.clean_params["folder"].lower() not in ("false", "0")
 
     @cached_property
     def type_filter(self):
         if "type" not in self.request.query_params:
-            return
+            return None
         try:
             element_type = self.selected_corpus.types.get(slug=self.clean_params["type"])
         except ElementType.DoesNotExist:
@@ -645,7 +645,7 @@ class ElementsListBase(CorpusACLMixin, DestroyModelMixin, ListAPIView):
         value = self.clean_params.get("metadata_value")
         operator = self.clean_params.get("metadata_operator", "").lower().strip()
         if not any((name, value, operator)):
-            return
+            return None
 
         queryset = MetaData.objects.all()
         errors = defaultdict(list)
@@ -1633,7 +1633,7 @@ class ElementTranscriptions(ListAPIView):
     @property
     def is_recursive(self):
         if not self.request:
-            return
+            return None
         recursive = self.request.query_params.get("recursive")
         return recursive is not None and recursive.lower() not in ("false", "0")
 
diff --git a/arkindex/documents/date_parser.py b/arkindex/documents/date_parser.py
index 0b088dddd5293065f10177351ffe0f59d97993be..47a0ffb03159c67e92affc1b93d530bfab115c44 100644
--- a/arkindex/documents/date_parser.py
+++ b/arkindex/documents/date_parser.py
@@ -45,7 +45,7 @@ def year(raw_date):
     """
     match = re.match(r"^(?P<year>\d{4})$", raw_date)
     if not match:
-        return
+        return None
     date = {k: int(v) for k, v in match.groupdict().items()}
     date["type"] = DateType.Exact
     return (date, )
@@ -57,7 +57,7 @@ def year_month(raw_date):
     """
     match = re.match(r"^(?P<year>\d{4})-(?P<month>\d{1,2})$", raw_date)
     if not match:
-        return
+        return None
     date = {k: int(v) for k, v in match.groupdict().items()}
     date["type"] = DateType.Exact
     return (date, )
@@ -70,7 +70,7 @@ def year_month_day(raw_date):
     """
     match = re.match(r"^(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})$", raw_date)
     if not match:
-        return
+        return None
     date = {k: int(v) for k, v in match.groupdict().items()}
     date["type"] = DateType.Exact
     return (date, )
diff --git a/arkindex/documents/dates.py b/arkindex/documents/dates.py
index 10643931a25ef85ddc16eacf9fbb9c262278d8ef..34bfa852819f1267a401b6b3d9d3111ae20f98d6 100644
--- a/arkindex/documents/dates.py
+++ b/arkindex/documents/dates.py
@@ -64,7 +64,7 @@ class InterpretedDate(object):
         """
         for s, o in zip(tuple(self), tuple(other)):
             if s is None or o is None:
-                return
+                return None
             if s == o:
                 continue
             return s > o
diff --git a/arkindex/documents/indexer.py b/arkindex/documents/indexer.py
index 203722ec319c6fadd9c9ba537d582693a05d26b7..f4f57ea0c2e1b0e5286f8b592fb23369bcae51ff 100644
--- a/arkindex/documents/indexer.py
+++ b/arkindex/documents/indexer.py
@@ -221,7 +221,7 @@ class Indexer(object):
 
     def hash_worker(self, worker_version):
         if not worker_version:
-            return
+            return None
 
         return worker_version.worker.name
 
diff --git a/arkindex/documents/management/commands/bootstrap.py b/arkindex/documents/management/commands/bootstrap.py
index 3ca2dacd4a0fbdfc5e63450c7c7c5e2d4664dbd2..aa3bfe85c19d61845d2d2740f2c589837da08b71 100644
--- a/arkindex/documents/management/commands/bootstrap.py
+++ b/arkindex/documents/management/commands/bootstrap.py
@@ -94,7 +94,7 @@ class Command(BaseCommand):
                 self.success(f"Image server {server.id} created")
             except IntegrityError as e:
                 self.fail(f"Failed to create image server: {e}")
-                return
+                return None
         return server
 
     def handle(self, **options):
diff --git a/arkindex/documents/models.py b/arkindex/documents/models.py
index e100e2b25e974602c3522ac1ac5c85c9892d9bc3..f8fda6ea2c291cab4cfb10f8d0accefff5d5dd6c 100644
--- a/arkindex/documents/models.py
+++ b/arkindex/documents/models.py
@@ -644,7 +644,7 @@ class Element(IndexableModel):
         Cropped IIIF URL for this element's image, if there is one.
         """
         if not self.polygon or not self.image_id:
-            return
+            return None
 
         from arkindex.project.tools import bounding_box
         x, y, width, height = bounding_box(self.polygon)
@@ -660,7 +660,7 @@ class Element(IndexableModel):
         Same as `iiif_url`, but resized to up to 400 pixels and with rotation and mirroring
         """
         if not self.polygon or not self.image_id:
-            return
+            return None
 
         from arkindex.project.tools import bounding_box
         x, y, width, height = bounding_box(self.polygon)
@@ -1159,7 +1159,7 @@ class MetaData(InterpretedDateMixin, models.Model):
     @property
     def raw_dates(self):
         if self.type != MetaType.Date:
-            return
+            return None
         return self.value
 
     def clean(self):
diff --git a/arkindex/documents/serializers/elements.py b/arkindex/documents/serializers/elements.py
index 7c7099022611581f7974ae4d89934bd158c6a8b8..ad9b227200b2c559b7fac1e946c58522fc977e54 100644
--- a/arkindex/documents/serializers/elements.py
+++ b/arkindex/documents/serializers/elements.py
@@ -406,7 +406,7 @@ class ElementTinySerializer(serializers.ModelSerializer):
         This method ensures the zone attribute is None.
         """
         if not element.image_id or not element.polygon:
-            return
+            return None
         return ZoneSerializer(element).data
 
     class Meta:
@@ -599,7 +599,7 @@ class ElementSerializer(ElementTinySerializer):
     @cached_property
     def element_rights(self):
         if not self.instance:
-            return
+            return None
 
         user = self.context["request"].user
         level = get_max_level(user, self.instance.corpus)
diff --git a/arkindex/documents/serializers/light.py b/arkindex/documents/serializers/light.py
index 6a8189eebbd6e543a9af0ffa2d3bee446ac20f99..3d6ebce7ea5f31f6efd0a4fe413d674e15be0c02 100644
--- a/arkindex/documents/serializers/light.py
+++ b/arkindex/documents/serializers/light.py
@@ -59,7 +59,7 @@ class ElementZoneSerializer(ElementLightSerializer):
         This method ensures the zone attribute is None.
         """
         if not element.image_id or not element.polygon:
-            return
+            return None
         return ZoneLightSerializer(element).data
 
     class Meta(ElementLightSerializer.Meta):
diff --git a/arkindex/documents/tests/test_edit_elementpath.py b/arkindex/documents/tests/test_edit_elementpath.py
index 21455699fdda5f61a5825ea0652c32827f92db3a..866aa77cde00fe5f450571a4d28e874c92c03805 100644
--- a/arkindex/documents/tests/test_edit_elementpath.py
+++ b/arkindex/documents/tests/test_edit_elementpath.py
@@ -32,7 +32,7 @@ class TestEditElementPath(FixtureTestCase):
 
         if paths is None or len(paths) < 1:
             self.assertNotIn(elements[element_name].id, tree)
-            return
+            return None
 
         element_names = {e.id: e.name for e in elements.values()}
 
diff --git a/arkindex/images/serializers.py b/arkindex/images/serializers.py
index 1b0805674f253a082a593f45c4438c27bdbb117a..05709481eaa9944a0702fc14735bdce98ae1306a 100644
--- a/arkindex/images/serializers.py
+++ b/arkindex/images/serializers.py
@@ -59,7 +59,7 @@ class ImageSerializer(serializers.ModelSerializer):
     @extend_schema_field(serializers.CharField(allow_null=True))
     def get_s3_url(self, obj):
         if "request" not in self.context:
-            return
+            return None
         # Only allow the S3 URL for admins or Ponos tasks
         if is_admin_or_ponos_task(self.context["request"]):
             return obj.s3_url
diff --git a/arkindex/ponos/serializers.py b/arkindex/ponos/serializers.py
index 932cc7c0c9586702826cabe665afc0adba0c47f9..9bc7a5c63659b046adb1f48490c64f1c95913137 100644
--- a/arkindex/ponos/serializers.py
+++ b/arkindex/ponos/serializers.py
@@ -225,7 +225,7 @@ class ArtifactSerializer(serializers.ModelSerializer):
         """Only add the PUT url to store the file for agents during creation"""
         request = self.context.get("request")
         if not request or request.method != "POST":
-            return
+            return None
         return obj.s3_put_url
 
     def validate_path(self, path):
diff --git a/arkindex/process/models.py b/arkindex/process/models.py
index 94d041202912e84b7f43ced2a9b347311fd3936d..5699d7c6a33e5dd7c7fe91a311d31e767a779207 100644
--- a/arkindex/process/models.py
+++ b/arkindex/process/models.py
@@ -806,13 +806,13 @@ class WorkerVersion(models.Model):
     @property
     def docker_command(self):
         if "docker" not in self.configuration:
-            return
+            return None
         return self.configuration["docker"].get("command")
 
     @property
     def docker_shm_size(self):
         if "docker" not in self.configuration:
-            return
+            return None
         return self.configuration["docker"].get("shm_size")
 
 
diff --git a/arkindex/process/serializers/files.py b/arkindex/process/serializers/files.py
index 497aa2e5f5a57a7f25cead7153b48b1c0ad91ce0..3dbc77b7997981be8d8adceb7b05906c9bb1d8c0 100644
--- a/arkindex/process/serializers/files.py
+++ b/arkindex/process/serializers/files.py
@@ -40,7 +40,7 @@ class DataFileSerializer(serializers.ModelSerializer):
     @extend_schema_field(serializers.CharField(allow_null=True))
     def get_s3_url(self, obj):
         if "request" not in self.context:
-            return
+            return None
         # Only allow the S3 URL for ponos tasks of Files or IIIF processes or admins
         request = self.context["request"]
         if is_admin_or_ponos_task(request):
diff --git a/arkindex/project/aws.py b/arkindex/project/aws.py
index 659f37326a0e132505e1fb4b63a7729e668ba328..51b392337e134b4fa7933d4a928c197cfe41ed2c 100644
--- a/arkindex/project/aws.py
+++ b/arkindex/project/aws.py
@@ -64,7 +64,7 @@ def requires_s3_object(func):
             logger.debug(
                 f"Function {func.__name__} requires file to have s3_object property, skipping"
             )
-            return
+            return None
         return func(self, *args, **kwargs)
     return wrapper
 
@@ -92,7 +92,7 @@ class S3FileMixin(object):
 
     def get_s3_object(self):
         if not self.s3_bucket or not self.s3_key:
-            return
+            return None
         return s3.Object(self.s3_bucket, self.s3_key)
 
     s3_object = cached_property(get_s3_object)
diff --git a/arkindex/project/gis.py b/arkindex/project/gis.py
index 8f80e295c1704a5322a9ed3bae8afdb835101e93..3b02fc4a4dca6ca5c3fcaf6a409ef80391ffeb7b 100644
--- a/arkindex/project/gis.py
+++ b/arkindex/project/gis.py
@@ -14,7 +14,7 @@ def ensure_linear_ring(value):
     # Polygons are nullable, so this can get called with None values;
     # if we had a non-null field, null values would be handled elsewhere by Django.
     if value is None:
-        return
+        return None
 
     if isinstance(value, str):
         value = GEOSGeometry(value, srid=0)
diff --git a/arkindex/project/rq_overrides.py b/arkindex/project/rq_overrides.py
index ae53b22aed70ff902fd288a626fd67868bc80d04..82e109a8d5e9b21543ec136f43f6da7289d2e586 100644
--- a/arkindex/project/rq_overrides.py
+++ b/arkindex/project/rq_overrides.py
@@ -10,13 +10,13 @@ from rq.utils import as_text, decode_redis_hash
 
 def as_int(value) -> Optional[int]:
     if value is None:
-        return
+        return None
     return int(value)
 
 
 def as_float(value) -> Optional[float]:
     if value is None:
-        return
+        return None
     return float(value)
 
 
diff --git a/arkindex/project/validators.py b/arkindex/project/validators.py
index 15fb732317819916a9bcae0c15d42596c0fab3f3..7c5cdbe9fc64c00213d0ebf9d238467cfda818b6 100644
--- a/arkindex/project/validators.py
+++ b/arkindex/project/validators.py
@@ -41,7 +41,7 @@ class ConditionalUniqueValidator(serializers.UniqueTogetherValidator):
 
     def __call__(self, attrs, serializer):
         if not self.condition(attrs):
-            return
+            return None
         return super().__call__(attrs, serializer)
 
 
diff --git a/arkindex/training/management/commands/migrate_workers.py b/arkindex/training/management/commands/migrate_workers.py
index 51e15165089905cc44b4063e851087dec1dfcbac..8408d89e41f75771a643e9544864a5649d44a73a 100644
--- a/arkindex/training/management/commands/migrate_workers.py
+++ b/arkindex/training/management/commands/migrate_workers.py
@@ -32,7 +32,7 @@ def choose(instances, name_field="name", title="Pick one item", allow_skip=False
     # Easy immediate choices
     nb = instances.count()
     if nb == 0:
-        return
+        return None
     elif nb == 1:
         return instances.first()
 
@@ -54,7 +54,7 @@ def choose(instances, name_field="name", title="Pick one item", allow_skip=False
         if choice in choices:
             value = choices[choice]
             if value is None:
-                return
+                return None
             return instances.get(pk=choices[choice])
 
 
diff --git a/ruff.toml b/ruff.toml
index 749c24cac4220a4ad6b45c3db0ae3c6119e8625a..3b796847f5c9c83f858d2543ddda6c930fd47b23 100644
--- a/ruff.toml
+++ b/ruff.toml
@@ -8,5 +8,7 @@ quote-style = "double"
 select = ["Q0", "F", "W", "E",
     # flake8-return: unnecessary-return-none
     "RET501",
+    # flake8-return: implicit-return-value
+    "RET502",
 ]
 ignore = ["E501"]