diff --git a/PKG-INFO b/PKG-INFO
index 5de3f064505bd964308ad99af07b5387d6c0dca1..c27c44f2a7804cc3922dfd614a561d9d92595adf 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 6.3.1
+Version: 6.4.0
 Summary: Software Heritage data model
 Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
 Author: Software Heritage developers
diff --git a/swh.model.egg-info/PKG-INFO b/swh.model.egg-info/PKG-INFO
index 5de3f064505bd964308ad99af07b5387d6c0dca1..c27c44f2a7804cc3922dfd614a561d9d92595adf 100644
--- a/swh.model.egg-info/PKG-INFO
+++ b/swh.model.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 6.3.1
+Version: 6.4.0
 Summary: Software Heritage data model
 Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
 Author: Software Heritage developers
diff --git a/swh/model/git_objects.py b/swh/model/git_objects.py
index 41be6f2ea77ed6304e9435ed72b47a7281f8d9df..cf258370efdaa7011dc77a10bb247885628509d8 100644
--- a/swh/model/git_objects.py
+++ b/swh/model/git_objects.py
@@ -412,7 +412,9 @@ def release_git_object(release: Union[Dict, model.Release]) -> bytes:
     return format_git_object_from_headers("tag", headers, release.message)
 
 
-def snapshot_git_object(snapshot: Union[Dict, model.Snapshot]) -> bytes:
+def snapshot_git_object(
+    snapshot: Union[Dict, model.Snapshot], *, ignore_unresolved: bool = False
+) -> bytes:
     """Formats a snapshot as a git-like object.
 
     Snapshots are a set of named branches, which are pointers to objects at any
@@ -456,6 +458,10 @@ def snapshot_git_object(snapshot: Union[Dict, model.Snapshot]) -> bytes:
       Note that, akin to directory manifests, there is no separator between
       entries. Because of symbolic branches, identifiers are of arbitrary
       length but are length-encoded to avoid ambiguity.
+
+    Args:
+      ignore_unresolved: if False (the default), raises an exception when
+        alias branches point to non-existing branches
     """
     if isinstance(snapshot, dict):
         # For backward compatibility
@@ -495,7 +501,7 @@ def snapshot_git_object(snapshot: Union[Dict, model.Snapshot]) -> bytes:
             ]
         )
 
-    if unresolved:
+    if unresolved and not ignore_unresolved:
         raise ValueError(
             "Branch aliases unresolved: %s"
             % ", ".join("%r -> %r" % x for x in unresolved),
diff --git a/swh/model/hypothesis_strategies.py b/swh/model/hypothesis_strategies.py
index 89fe6dec358d6a5641fca453f289581f43d746b1..19a8d89118f1e6b522b2f8af61ff6a1337515e38 100644
--- a/swh/model/hypothesis_strategies.py
+++ b/swh/model/hypothesis_strategies.py
@@ -131,6 +131,18 @@ def timestamps_d(**kwargs):
     min_seconds = datetime.datetime.min.replace(
         tzinfo=datetime.timezone.utc
     ).timestamp()
+
+    # in Python 3.9, datetime.datetime.max is 9999-12-31T23:59:59.999999, which
+    # means its .timestamp() is 253402300799.999999 in UTC. Unfortunately, because of
+    # flotting-point loss of precision, this is rounded up to 253402300800.0, which
+    # is the timestamp of 10000-01-01T00:00:00 in UTC, which cannot be passed to
+    # datetime.datetime.fromtimestamp because it overflows.
+    # To work around this issue, we move from max_seconds and min_seconds one second
+    # closer to Epoch, which is more than enough (actually, subtracting 20ms from
+    # max_seconds is enough).
+    max_seconds -= 1
+    min_seconds += 1
+
     defaults = dict(
         seconds=integers(min_seconds, max_seconds),
         microseconds=integers(0, 1000000 - 1),
diff --git a/swh/model/model.py b/swh/model/model.py
index 1073cc61cf4623ba65428b164466b82d4ad35b6c..8910db8cf98e0b6738e8f7c1f40326f676094583 100644
--- a/swh/model/model.py
+++ b/swh/model/model.py
@@ -197,7 +197,9 @@ class BaseModel:
 
     def check(self) -> None:
         """Performs internal consistency checks, and raises an error if one fails."""
-        attr.validate(self)
+        # without the type-ignore comment below, attr >= 22.1.0 causes mypy to report:
+        #   Argument 1 has incompatible type "BaseModel"; expected "AttrsInstance"
+        attr.validate(self)  # type: ignore[arg-type]
 
 
 def _compute_hash_from_manifest(manifest: bytes) -> Sha1Git:
@@ -741,7 +743,9 @@ class Snapshot(HashableObject, BaseModel):
     id = attr.ib(type=Sha1Git, validator=type_validator(), default=b"", repr=hash_repr)
 
     def _compute_hash_from_attributes(self) -> bytes:
-        return _compute_hash_from_manifest(git_objects.snapshot_git_object(self))
+        return _compute_hash_from_manifest(
+            git_objects.snapshot_git_object(self, ignore_unresolved=True)
+        )
 
     @classmethod
     def from_dict(cls, d):
diff --git a/swh/model/tests/test_identifiers.py b/swh/model/tests/test_identifiers.py
index 793e6d5b3aa6f931a1afc8ca17f7b3be61c4e90d..d5a0eb30cc67f51725037b732a744348b5dbb726 100644
--- a/swh/model/tests/test_identifiers.py
+++ b/swh/model/tests/test_identifiers.py
@@ -755,8 +755,14 @@ class SnapshotIdentifier(unittest.TestCase):
         )
 
     def test_unresolved(self):
+        self.assertEqual(
+            Snapshot.from_dict(remove_id(self.unresolved)).id, self.unresolved["id"]
+        )
+
+    def test_git_object_unresolved(self):
         with self.assertRaisesRegex(ValueError, "b'foo' -> b'bar'"):
-            Snapshot.from_dict(remove_id(self.unresolved))
+            git_objects.snapshot_git_object(self.unresolved)
+        git_objects.snapshot_git_object(self.unresolved, ignore_unresolved=True)
 
     def test_all_types(self):
         self.assertEqual(