diff --git a/swh/model/model.py b/swh/model/model.py
index 5e00cc61b6e58bbc9ab42132209ecbffd7606158..1496831643dd1b5c80b28bebdb1a6d0390d24b20 100644
--- a/swh/model/model.py
+++ b/swh/model/model.py
@@ -1396,9 +1396,9 @@ class Directory(HashableObjectWithManifest, BaseModel):
             raw_manifest = git_objects.directory_git_object(invalid_directory)
 
         # 2. look for duplicated entries:
-        entries_by_name: Dict[
-            bytes, Dict[str, List[DirectoryEntry]]
-        ] = collections.defaultdict(lambda: collections.defaultdict(list))
+        entries_by_name: Dict[bytes, Dict[str, List[DirectoryEntry]]] = (
+            collections.defaultdict(lambda: collections.defaultdict(list))
+        )
         for entry in entries:
             entries_by_name[entry.name][entry.type].append(entry)
 
@@ -1523,7 +1523,7 @@ class Content(BaseContent):
                 raise ValueError("ctime must be a timezone-aware datetime.")
 
     def to_dict(self):
-        content = super(Content, self.with_data()).to_dict()
+        content = super(Content, self.with_data(raise_if_missing=False)).to_dict()
         for k in ("get_data", "data", "ctime"):
             if content[k] is None:
                 del content[k]
@@ -1548,18 +1548,22 @@ class Content(BaseContent):
             d["ctime"] = dateutil.parser.parse(d["ctime"])
         return super().from_dict(d, use_subclass=False)
 
-    def with_data(self) -> "Content":
-        """Loads the `data` attribute; meaning that it is guaranteed not to
-        be None after this call.
+    def with_data(self, raise_if_missing: bool = True) -> "Content":
+        """Loads the ``data`` attribute if ``get_data`` is not :const:`None`.
 
         This call is almost a no-op, but subclasses may overload this method
-        to lazy-load data (eg. from disk or objstorage)."""
+        to lazy-load data (eg. from disk or objstorage).
+
+        Args:
+            raise_if_missing: if :const:`True` (default), raise :class:`MissingData`
+                exception if no data is attached to content object
+        """
         if self.data is not None:
             return self
         new_data = None
         if self.get_data is not None:
             new_data = self.get_data()
-        if new_data is None:
+        if new_data is None and raise_if_missing:
             raise MissingData("Content data and get_data are both None.")
         return attr.evolve(self, data=new_data, get_data=None)
 
diff --git a/swh/model/tests/test_from_disk.py b/swh/model/tests/test_from_disk.py
index ee599538cdd224aeb2cacbd04046587fe1b72d27..234035f1da2fa9faa44aef2f0a70f7f555bbd910 100644
--- a/swh/model/tests/test_from_disk.py
+++ b/swh/model/tests/test_from_disk.py
@@ -79,8 +79,10 @@ class TestDiskBackedContent(unittest.TestCase):
             fd.write(b"foo bar")
             fd.seek(0)
             content_with_data = content.with_data()
+            assert content.to_dict() == content_with_data.to_dict()
 
         assert expected_content == content_with_data
+        assert expected_content.to_dict() == content_with_data.to_dict()
 
     def test_lazy_data(self):
         with tempfile.NamedTemporaryFile(mode="w+b") as fd:
diff --git a/swh/model/tests/test_model.py b/swh/model/tests/test_model.py
index 2a12ec6ef20da96630ce0baeb5c3e7fbb032e2f5..5fb20591c7a27c0983cc2bc60fccddc352711459 100644
--- a/swh/model/tests/test_model.py
+++ b/swh/model/tests/test_model.py
@@ -814,6 +814,15 @@ def test_content_data():
         blake2s256=b"qux",
     )
     assert c.with_data() == c
+    assert c.to_dict() == {
+        "sha1": b"foo",
+        "sha1_git": b"bar",
+        "sha256": b"baz",
+        "blake2s256": b"qux",
+        "length": 42,
+        "status": "visible",
+        "data": b"foo",
+    }
 
 
 def test_content_data_missing():
@@ -828,6 +837,15 @@ def test_content_data_missing():
     with pytest.raises(MissingData):
         c.with_data()
 
+    assert c.to_dict() == {
+        "sha1": b"foo",
+        "sha1_git": b"bar",
+        "sha256": b"baz",
+        "blake2s256": b"qux",
+        "length": 42,
+        "status": "visible",
+    }
+
 
 @given(strategies.present_contents_d())
 def test_content_from_dict(content_d):