diff --git a/components/micropython/usermodule/mp_sys_kernel.c b/components/micropython/usermodule/mp_sys_kernel.c
index ac045ab7e943e5825e8178e68e70b3bc5695cff3..035eef968ea9e0a428f58583d4b81c052da1c166 100644
--- a/components/micropython/usermodule/mp_sys_kernel.c
+++ b/components/micropython/usermodule/mp_sys_kernel.c
@@ -8,6 +8,7 @@
 #include "py/obj.h"
 #include "py/runtime.h"
 #include "st3m_console.h"
+#include "st3m_fs_sd.h"
 #include "st3m_io.h"
 #include "st3m_usb.h"
 #include "st3m_version.h"
@@ -407,6 +408,26 @@ STATIC mp_obj_t mp_battery_charging(void) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_battery_charging_obj, mp_battery_charging);
 
+STATIC mp_obj_t mp_sd_oem(void) {
+    int32_t res = st3m_fs_sd_oem_id();
+    if (res == -1) {
+        return mp_const_none;
+    }
+    return mp_obj_new_int(res);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_sd_oem_obj, mp_sd_oem);
+
+STATIC mp_obj_t mp_sd_mfg(void) {
+    int32_t res = st3m_fs_sd_mfg_id();
+    if (res == -1) {
+        return mp_const_none;
+    }
+    return mp_obj_new_int(res);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_sd_mfg_obj, mp_sd_mfg);
+
 STATIC const mp_rom_map_elem_t globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_scheduler_snapshot),
       MP_ROM_PTR(&mp_scheduler_snapshot_obj) },
@@ -422,6 +443,8 @@ STATIC const mp_rom_map_elem_t globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_i2c_scan), MP_ROM_PTR(&mp_i2c_scan_obj) },
     { MP_ROM_QSTR(MP_QSTR_battery_charging),
       MP_ROM_PTR(&mp_battery_charging_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sd_oem), MP_ROM_PTR(&mp_sd_oem_obj) },
+    { MP_ROM_QSTR(MP_QSTR_sd_mfg), MP_ROM_PTR(&mp_sd_mfg_obj) },
 
     { MP_ROM_QSTR(MP_QSTR_RUNNING), MP_ROM_INT(eRunning) },
     { MP_ROM_QSTR(MP_QSTR_READY), MP_ROM_INT(eReady) },
diff --git a/components/st3m/st3m_fs_sd.c b/components/st3m/st3m_fs_sd.c
index 99b8ce3ebfc365a554e2e9f1df4e4e58de585908..3721365f1ca22cbe72563573ac1dcb49cbfe4ca6 100644
--- a/components/st3m/st3m_fs_sd.c
+++ b/components/st3m/st3m_fs_sd.c
@@ -263,6 +263,10 @@ static esp_err_t _st3m_fs_sd_probe_unlocked(st3m_fs_sd_props_t *props) {
                  esp_err_to_name(ret));
         return ret;
     }
+    // useful for collecting info about SDcards that are problematic, ask users
+    // about this to potentially add to blocklist. Also in about menu.
+    ESP_LOGI(TAG, "SD CID: mfg_id: %i, oem_id: %i, date: %i", _card.cid.mfg_id,
+             _card.cid.oem_id, _card.cid.date);
 
     _status = st3m_fs_sd_status_probed;
 
@@ -309,6 +313,22 @@ esp_err_t st3m_fs_sd_probe(st3m_fs_sd_props_t *props) {
     return ret;
 }
 
+int32_t st3m_fs_sd_oem_id() {
+    if (_status == st3m_fs_sd_status_probed ||
+        _status == st3m_fs_sd_status_mounted) {
+        return _card.cid.oem_id;
+    }
+    return -1;
+}
+
+int32_t st3m_fs_sd_mfg_id() {
+    if (_status == st3m_fs_sd_status_probed ||
+        _status == st3m_fs_sd_status_mounted) {
+        return _card.cid.mfg_id;
+    }
+    return -1;
+}
+
 int32_t st3m_fs_sd_read10(uint8_t lun, uint32_t lba, uint32_t offset,
                           void *buffer, uint32_t bufsize) {
     if (offset != 0) {
diff --git a/components/st3m/st3m_fs_sd.h b/components/st3m/st3m_fs_sd.h
index 2f058acac863d5045dadda921febe3d62ce7c14d..29e65aa61e31a7bee7a329145def073f3da7d139 100644
--- a/components/st3m/st3m_fs_sd.h
+++ b/components/st3m/st3m_fs_sd.h
@@ -42,6 +42,12 @@ esp_err_t st3m_fs_sd_unmount(void);
 // No-op if card is already ejected.
 esp_err_t st3m_fs_sd_eject(void);
 
+// for identifying sdcards in python land to warn about known problematic
+// SDcards
+int32_t st3m_fs_sd_oem_id();
+
+int32_t st3m_fs_sd_mfg_id();
+
 // SCSI Read (10) and Write (10) compatible operations. Offset must be 0. If an
 // error occurs during the read/write operation, the card will be checked for
 // errors, and might get ejected if deemed uanvailable/broken.
diff --git a/python_payload/apps/gr33nhouse/__init__.py b/python_payload/apps/gr33nhouse/__init__.py
index 5d0a9aa23d5fbe40c98239cf4cb567b15e7b8db9..e3089becf3ff3b8363144b6966718e2377998e14 100644
--- a/python_payload/apps/gr33nhouse/__init__.py
+++ b/python_payload/apps/gr33nhouse/__init__.py
@@ -4,6 +4,7 @@ from st3m.input import InputState
 from st3m.ui.interactions import ScrollController
 from st3m.ui import colours
 from st3m.ui.view import ViewManager
+from st3m.utils import sd_card_unreliable
 import st3m.wifi
 from ctx import Context
 import network
@@ -16,6 +17,7 @@ from .manual import ManualInputView
 class ViewState(Enum):
     CONTENT = 1
     NO_INTERNET = 2
+    BAD_SDCARD = 3
 
 
 class Gr33nhouseApp(Application):
@@ -30,6 +32,7 @@ class Gr33nhouseApp(Application):
         self.background = Flow3rView()
         self._sc = ScrollController()
         self._sc.set_item_count(3)
+        self.acceptSdCard = False
 
         self.state = ViewState.CONTENT
 
@@ -38,6 +41,37 @@ class Gr33nhouseApp(Application):
         return True
 
     def draw(self, ctx: Context) -> None:
+        if self.state == ViewState.BAD_SDCARD:
+            ctx.move_to(0, 0)
+            ctx.rgb(*colours.BLACK)
+            ctx.rectangle(
+                -120.0,
+                -120.0,
+                240.0,
+                240.0,
+            ).fill()
+
+            ctx.save()
+            ctx.rgb(*colours.WHITE)
+            ctx.font = "Camp Font 3"
+            ctx.font_size = 18
+            ctx.text_align = ctx.CENTER
+            ctx.text_baseline = ctx.MIDDLE
+
+            ctx.move_to(0, -15)
+            ctx.text("Unreliable SD card detected!")
+            ctx.move_to(0, 5)
+            ctx.text("Please replace it.")
+
+            ctx.gray(0.75)
+            ctx.move_to(0, 40)
+            ctx.font_size = 16
+            ctx.text("Press the app button to")
+            ctx.move_to(0, 55)
+            ctx.text("continue anyway.")
+
+            ctx.restore()
+            return
         if self.state == ViewState.NO_INTERNET:
             ctx.move_to(0, 0)
             ctx.rgb(*colours.BLACK)
@@ -106,6 +140,20 @@ class Gr33nhouseApp(Application):
 
         self.background.think(ins, delta_ms)
 
+        if not self.acceptSdCard:
+            if sd_card_unreliable():
+                self.state = ViewState.BAD_SDCARD
+            else:
+                self.acceptSdCard = True
+
+        if self.state == ViewState.BAD_SDCARD and self.input.buttons.app.middle.pressed:
+            self.state = ViewState.CONTENT
+            self.acceptSdCard = True
+            return
+
+        if self.state == ViewState.BAD_SDCARD:
+            return
+
         if not self.is_active():
             return
 
diff --git a/python_payload/apps/updat3r/__init__.py b/python_payload/apps/updat3r/__init__.py
index 1f3a31759831d59ab4fc8181309bc22cad6d35b8..cc40cec17c92253fdf0fc53c807521b0cd603c94 100644
--- a/python_payload/apps/updat3r/__init__.py
+++ b/python_payload/apps/updat3r/__init__.py
@@ -1,7 +1,7 @@
 from st3m.application import Application, ApplicationContext
 from st3m.input import InputState
 from st3m.goose import Optional
-from st3m.utils import sd_card_plugged
+from st3m.utils import sd_card_plugged, sd_card_unreliable
 from ctx import Context
 import sys_kernel
 import urequests
@@ -58,9 +58,9 @@ class UpdaterApp(Application):
             and not self.fetched_version
             and not self.vm.transitioning
         ):
-            ctx.move_to(0, 40)
+            ctx.move_to(0, 45)
             ctx.text("press the app button to")
-            ctx.move_to(0, 55)
+            ctx.move_to(0, 60)
             ctx.text("enter Wi-Fi settings")
 
     def version_to_number(self, version_raw: str):
@@ -185,10 +185,19 @@ class UpdaterApp(Application):
         if not self._sd_present:
             return
 
+        if sd_card_unreliable():
+            self._state_text = (
+                "Your SD card model is\n"
+                "known to cause errors.\n"
+                "It is recommended to swap it!\n"
+                "Flash firmware via USB instead\nhttps://flow3r.garden/flasher"
+            )
+            return
+
         if self._sd_failed:
             self._state_text = (
                 "don't panic, but...\na weird SD bug happened D:\nturn off and on flow3r power (ha)\n"
-                "and retry. some SD cards don't\nwork for this at all tho :/\n\n"
+                "and retry. Please report the \nSD IDs in the About menu to the team\n\n"
                 "if this error repeats try\nhttps://flow3r.garden/flasher\ninstead!"
             )
             return
diff --git a/python_payload/st3m/about.py b/python_payload/st3m/about.py
index ee2b0a65b36fa4f572e29532df9f6a4bc6c1ebbc..48534a0961f680c2344ddf9418c71d1fc4a05b39 100644
--- a/python_payload/st3m/about.py
+++ b/python_payload/st3m/about.py
@@ -1,10 +1,11 @@
 from ctx import Context
 from st3m import InputState, Responder
 from st3m.ui.view import BaseView, ViewTransitionSwipeRight
-from st3m.utils import tau, sd_card_plugged
+from st3m.utils import tau, sd_card_plugged, sd_card_unreliable
 from st3m.goose import List, Optional
 import math
 import os
+import sys_kernel
 
 
 class Screen(Responder):
@@ -157,7 +158,11 @@ class SpaceScreen(Screen):
         ctx.move_to(0, 21)
         ctx.font = "Camp Font 2"
         if self.sd_plugged:
-            ctx.text("SD Card")
+            if sd_card_unreliable():
+                ctx.font_size = 20
+                ctx.text("SD Card (Unreliable model)")
+            else:
+                ctx.text("SD Card")
         else:
             ctx.text("No SD Detected")
 
@@ -175,6 +180,8 @@ class SpaceScreen(Screen):
         ctx.font_size = 15
         ctx.move_to(0, 49)
         ctx.text(self.sd_text)
+        ctx.move_to(0, 67)
+        ctx.text("ID: " + str(sys_kernel.sd_oem()) + ", " + str(sys_kernel.sd_mfg()))
 
 
 class About(BaseView):
diff --git a/python_payload/st3m/utils.py b/python_payload/st3m/utils.py
index 924c6b032203c52ea33220438617d546fd622bf4..c43c5b5a2dfb01a332ea873cd916ac43fd269d17 100644
--- a/python_payload/st3m/utils.py
+++ b/python_payload/st3m/utils.py
@@ -147,6 +147,22 @@ def sd_card_plugged() -> bool:
         return False
 
 
+def sd_card_unreliable():
+    if not sd_card_plugged():
+        return None
+    elif sys_kernel.sd_oem() == 21930 and sys_kernel.sd_mfg() == 200:
+        # for SDcards that have shown to reliably fail to download a firmware update
+        # these occasionally fail to download apps too. This seems to be likely an issue
+        # with the Espressif SDIO stack or PHY as there are many reports like this over many years
+        # These cards tend to work fine in an SD card reader on a PC
+        # The card with mfg id 200 and oem id 21930 is from the supplied SDcards at CCCamp 2023
+        # We had identified two variants so far from that batch, the other variant (0, 12288) seems to have been fine
+        # Two of each type had been tested so far.
+        return True
+    else:
+        return False
+
+
 def is_simulator() -> bool:
     return sys_kernel.hardware_version() == "simulator"