diff --git a/src/_zkapauthorizer/_storage_server.py b/src/_zkapauthorizer/_storage_server.py
index 468d683d6b4952f4fee54b8ecc8407c67f62f4c2..5fdf3e473b27086abd680481b736ecd9888695f4 100644
--- a/src/_zkapauthorizer/_storage_server.py
+++ b/src/_zkapauthorizer/_storage_server.py
@@ -90,6 +90,17 @@ SLOT_HEADER_SIZE = 468
 LEASE_TRAILER_SIZE = 4
 
 
+class NewLengthRejected(Exception):
+    """
+    A non-None value for ``new_length`` was given to
+    ``slot_testv_and_readv_and_writev``.
+
+    This is disallowed by ZKAPAuthorizer because of the undesirable
+    interactions with the current spending protocol and because there are no
+    known real-world use-cases for this usage.
+    """
+
+
 @attr.s
 class _ValidationResult(object):
     """
@@ -457,6 +468,13 @@ class ZKAPAuthorizerStorageServer(Referenceable):
         # part of this call.
         now = self._clock.seconds()
 
+        # We're not exactly sure what to do with mutable container truncations
+        # and the official client doesn't ever use that feature so just
+        # disable it by rejecting all attempts here.
+        for (testv, writev, new_length) in tw_vectors.values():
+            if new_length is not None:
+                raise NewLengthRejected(new_length)
+
         # Check passes for cryptographic validity.
         validation = _ValidationResult.validate_passes(
             slot_testv_and_readv_and_writev_message(storage_index),
diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py
index c439874b7d6b1560cc881138d4fcf8a50dc4beb7..61b401967aa131463f7e83f03ba03bceda85c430 100644
--- a/src/_zkapauthorizer/tests/strategies.py
+++ b/src/_zkapauthorizer/tests/strategies.py
@@ -917,13 +917,13 @@ def slot_test_and_write_vectors():
         TestAndWriteVectors,
         slot_test_vectors(),
         slot_data_vectors(),
-        one_of(
-            # The new length might be omitted completely.
-            just(None),
-            # Or it might be given as an integer.  Allow a zero size which
-            # means "delete this share" in this context.
-            sizes(),
-        ),
+        # The underlying Tahoe-LAFS storage protocol allows None or an integer
+        # here (new_length) to set the size of the mutable container.  The
+        # real Tahoe-LAFS storage client never uses this feature and always
+        # passes None.  There are undesirable interactions between non-None
+        # values for new_length and our spending protocol.  Therefore, we
+        # disable non-None values.  So don't generate any here.
+        just(None),
     )
 
 
diff --git a/src/_zkapauthorizer/tests/test_storage_server.py b/src/_zkapauthorizer/tests/test_storage_server.py
index aba0ad094dc3ddb4e274b70b68b3a3e6237e8704..7e334d79e6f8fca00f16170d46dca9b2bd1f1513 100644
--- a/src/_zkapauthorizer/tests/test_storage_server.py
+++ b/src/_zkapauthorizer/tests/test_storage_server.py
@@ -31,7 +31,7 @@ from testtools.matchers import AfterPreprocessing, Equals, MatchesAll
 from twisted.internet.task import Clock
 from twisted.python.runtime import platform
 
-from .._storage_server import _ValidationResult
+from .._storage_server import NewLengthRejected, _ValidationResult
 from ..api import MorePassesRequired, ZKAPAuthorizerStorageServer
 from ..server.spending import RecordingSpender
 from ..storage_common import (
@@ -445,6 +445,66 @@ class PassValidationTests(TestCase):
             ),
         )
 
+    @given(
+        storage_index=storage_indexes(),
+        secrets=tuples(
+            write_enabler_secrets(),
+            lease_renew_secrets(),
+            lease_cancel_secrets(),
+        ),
+        sharenums=sharenum_sets(),
+        test_and_write_vectors_for_shares=slot_test_and_write_vectors_for_shares(),
+        new_length=integers(),
+    )
+    def test_mutable_new_length_rejected(
+        self,
+        storage_index,
+        secrets,
+        sharenums,
+        test_and_write_vectors_for_shares,
+        new_length,
+    ):
+        """
+        If ``new_length`` is not ``None`` then ``slot_testv_and_readv_and_writev``
+        rejects the operation.
+        """
+        tw_vectors = {
+            k: v.for_call() for (k, v) in test_and_write_vectors_for_shares.items()
+        }
+        # Change some tw_vector to have a non-None new_length.
+        sharenum, (testv, writev, ignored) = tw_vectors.popitem()
+        tw_vectors[sharenum] = (testv, writev, new_length)
+
+        required_pass_count = get_required_new_passes_for_mutable_write(
+            self.pass_value,
+            dict.fromkeys(tw_vectors.keys(), 0),
+            tw_vectors,
+        )
+        valid_passes = get_passes(
+            slot_testv_and_readv_and_writev_message(storage_index),
+            required_pass_count,
+            self.signing_key,
+        )
+
+        # Try to do a write with the non-None new_length and expect it to be
+        # rejected.
+        try:
+            result = self.storage_server.doRemoteCall(
+                "slot_testv_and_readv_and_writev",
+                (),
+                dict(
+                    passes=_encode_passes(valid_passes),
+                    storage_index=storage_index,
+                    secrets=secrets,
+                    tw_vectors=tw_vectors,
+                    r_vector=[],
+                ),
+            )
+        except NewLengthRejected:
+            pass
+        else:
+            self.fail("expected a failure but got {!r}".format(result))
+
     @given(
         storage_index=storage_indexes(),
         secrets=tuples(