diff --git a/epicardium/modules/bhi.c b/epicardium/modules/bhi.c
index baa2d16220be0754bcbb321ef04fa852a43d7a85..5cde7442827948075b7f3e32ccd9532165ab713e 100644
--- a/epicardium/modules/bhi.c
+++ b/epicardium/modules/bhi.c
@@ -315,7 +315,16 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
 			    bhi160_streams[sensor_type].queue,
 			    &data_vector,
 			    0) != pdTRUE) {
-			LOG_WARN("bhi160", "queue full for %d", sensor_type);
+			if (!bhi160_streams[sensor_type].was_full) {
+				LOG_WARN(
+					"bhi160",
+					"queue full for %d",
+					sensor_type
+				);
+			}
+			bhi160_streams[sensor_type].was_full = true;
+		} else {
+			bhi160_streams[sensor_type].was_full = false;
 		}
 
 		if (wakeup) {
diff --git a/epicardium/modules/max30001.c b/epicardium/modules/max30001.c
index 39379703ec292458a404a63346d4bf6258b04d84..1b6dfd7b2e52e9b362c835d3be9c3da6c3a66272 100644
--- a/epicardium/modules/max30001.c
+++ b/epicardium/modules/max30001.c
@@ -137,7 +137,12 @@ static void max30001_handle_samples(int16_t *sensor_data, int16_t n)
 
 		/* Discard overflow.  See discussion in !316. */
 		if (xQueueSend(max30001_stream.queue, &data, 0) != pdTRUE) {
-			LOG_WARN("max30001", "queue full");
+			if (!max30001_stream.was_full) {
+				LOG_WARN("max30001", "queue full");
+			}
+			max30001_stream.was_full = true;
+		} else {
+			max30001_stream.was_full = false;
 		}
 	}
 	interrupt_trigger(EPIC_INT_MAX30001_ECG);
diff --git a/epicardium/modules/max86150.c b/epicardium/modules/max86150.c
index 03527052c5b372d4a9ca30ae64d767d5ce51a79c..154705bfa685a4c8d8a9a31ba709cd1f98e50224 100644
--- a/epicardium/modules/max86150.c
+++ b/epicardium/modules/max86150.c
@@ -136,8 +136,13 @@ static int max86150_handle_sample(struct max86150_sensor_data *data)
 
 	/* Discard overflow.  See discussion in !316. */
 	if (xQueueSend(max86150_stream.queue, data, 0) != pdTRUE) {
-		LOG_WARN("max86150", "queue full");
+		if (!max86150_stream.was_full) {
+			LOG_WARN("max86150", "queue full");
+		}
+		max86150_stream.was_full = true;
 		return -EIO;
+	} else {
+		max86150_stream.was_full = false;
 	}
 
 	interrupt_trigger(EPIC_INT_MAX86150);
diff --git a/epicardium/modules/stream.h b/epicardium/modules/stream.h
index a953537aea4d1bb6a3aed755d0ec236098366781..fe23b860aacc96e01ecd6e92c6952ea7e67465c6 100644
--- a/epicardium/modules/stream.h
+++ b/epicardium/modules/stream.h
@@ -67,6 +67,12 @@ struct stream_info {
 	 * The function registered here should never block for a longer time.
 	 */
 	int (*poll_stream)();
+
+	/**
+	 * Set to true if the last write to ``queue`` failed because
+	 * the queue was full.
+	 */
+	bool was_full;
 };
 
 /**