diff --git a/src/encrypt.rs b/src/encrypt.rs
index d108cf37d7cb0bb59e2660a583a4ef7f4f6c6400..eba4f4b4b68b60382eeef28d29097a05699f692d 100644
--- a/src/encrypt.rs
+++ b/src/encrypt.rs
@@ -59,6 +59,11 @@ impl KeyState {
         }
     }
 
+    pub fn is_cleartext(&self) -> bool {
+        matches!(self.keys.enc, EncKey::NoCipher)
+            || matches!(self.keys.dec, DecKey::NoCipher)
+    }
+
     /// Updates with new keys, keeping the same sequence numbers
     pub fn rekey(&mut self, keys: Keys) {
         self.keys = keys
diff --git a/src/error.rs b/src/error.rs
index d3472500e75fd4c108099e212c21a5036b5ae941..7eed50f325ce0678d6e85b3849893fc7fb0ccb4d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -98,6 +98,7 @@ pub enum Error {
 
     // This state should not be reached, previous logic should have prevented it.
     // Create this using [`Error::bug()`] or [`.trap()`](TrapBug::trap).
+    // Location is currently disabled due to bloat.
     // #[snafu(display("Program bug {location}"))]
     // Bug { location: snafu::Location },
     /// Program bug
diff --git a/src/sshnames.rs b/src/sshnames.rs
index 97b179b5e8a6485ad8683cb7ba9376295c97c387..9b5bb6d40980c665feae8fbb5c0e41d050ac70f2 100644
--- a/src/sshnames.rs
+++ b/src/sshnames.rs
@@ -3,7 +3,7 @@
 //! Some identifiers are also listed directly in `packet.rs` derive attributes.
 //! Packet numbers are listed in `packets.rs`.
 //!
-//! This module also serves as index of SSH specifications.
+//! This module also serves as an index of SSH specifications.
 
 /// [RFC8731](https://tools.ietf.org/html/rfc8731)
 pub const SSH_NAME_CURVE25519: &str = "curve25519-sha256";
@@ -29,8 +29,8 @@ pub const SSH_NAME_AES256_CTR: &str = "aes256-ctr";
 /// OpenSSH [PROTOCOL.chacha20poly1305.txt](https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD)
 pub const SSH_NAME_CHAPOLY: &str = "chacha20-poly1305@openssh.com";
 /// OpenSSH [PROTOCOL](https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD).
-/// (No-one uses aes-gcm [RFC5647](https://tools.ietf.org/html/rfc5647) from the NSA, it fails to define mac negotiation
-/// sensibly and has horrible naming style)
+/// (No-one directly uses `AEAD_AES_256_GCM` [RFC5647](https://tools.ietf.org/html/rfc5647) from the NSA, it fails to define mac negotiation
+/// sensibly and has incongruous naming style)
 pub const SSH_NAME_AES256_GCM: &str = "aes256-gcm@openssh.com";
 
 /// [RFC6668](https://tools.ietf.org/html/rfc6668)
diff --git a/src/traffic.rs b/src/traffic.rs
index de8db59bd4a528e50feafed742400ef4f81ee7bd..36a9f22066b342f86ec45360e910772bd19a56bd 100644
--- a/src/traffic.rs
+++ b/src/traffic.rs
@@ -288,6 +288,16 @@ impl<'a> TrafOut<'a> {
             TxState::Write { idx, len } => (idx, len),
         };
 
+        // Sanity check
+        match p.category() {
+            packets::Category::All | packets::Category::Kex => (), // OK cleartext
+            _ => {
+                if keys.is_cleartext() {
+                    return Error::bug_msg("send cleartext")
+                }
+            }
+        }
+
         // Use the remainder of our buffer to write the packet. Payload starts
         // after the length and padding bytes which get filled by encrypt()
         let wbuf = &mut self.buf[len..];