diff --git a/changelog.d/14012.misc b/changelog.d/14012.misc
new file mode 100644
index 0000000000000000000000000000000000000000..9888dc6cc122d48a89d43c8ec7d812fa0841bbeb
--- /dev/null
+++ b/changelog.d/14012.misc
@@ -0,0 +1 @@
+Fix type annotations to be compatible with new annotations in development versions of twisted.
diff --git a/synapse/handlers/cas.py b/synapse/handlers/cas.py
index 7163af8004e37a2689872b877ba99d7fc5362a06..fc467bc7c13e1f986e13747943a63ca9b9265ae6 100644
--- a/synapse/handlers/cas.py
+++ b/synapse/handlers/cas.py
@@ -130,6 +130,9 @@ class CasHandler:
         except PartialDownloadError as pde:
             # Twisted raises this error if the connection is closed,
             # even if that's being used old-http style to signal end-of-data
+            # Assertion is for mypy's benefit. Error.response is Optional[bytes],
+            # but a PartialDownloadError should always have a non-None response.
+            assert pde.response is not None
             body = pde.response
         except HttpResponseException as e:
             description = (
diff --git a/synapse/handlers/ui_auth/checkers.py b/synapse/handlers/ui_auth/checkers.py
index a744d68c648a5e38c7c9f0925bf677f639221847..332edcca24e5ef69d2e4f848df108cdf410e27f1 100644
--- a/synapse/handlers/ui_auth/checkers.py
+++ b/synapse/handlers/ui_auth/checkers.py
@@ -119,6 +119,9 @@ class RecaptchaAuthChecker(UserInteractiveAuthChecker):
         except PartialDownloadError as pde:
             # Twisted is silly
             data = pde.response
+            # For mypy's benefit. A general Error.response is Optional[bytes], but
+            # a PartialDownloadError.response should be bytes AFAICS.
+            assert data is not None
             resp_body = json_decoder.decode(data.decode("utf-8"))
 
         if "success" in resp_body: