From 616aa59e025613eea532c699df56cfbb71bae8d9 Mon Sep 17 00:00:00 2001 From: comms_engineer Date: Fri, 3 Jul 2026 00:31:15 +0000 Subject: [PATCH] Improve error handling: log silently swallowed exceptions Replace bare 'except Exception: pass' blocks with proper logging across MeshCore_Dynamic_Interface.py and MeshCore_Interface.py. MeshCore_Dynamic_Interface.py: - Log radio config failures (set_radio) - Log RNSBIND_REQ, heartbeat, and response send failures - Log base64 decode errors in debug mode - Log reassembly failures with pkt_id and sender context - Log fragment enqueue failures in processOutgoing MeshCore_Interface.py: - Log config file read errors - Log initial contact fetch failures - Remove redundant nested try/except in transport registration - Log async setup timeout context instead of silently passing - Log sender key normalization fallbacks at debug level - Log peer mapping update failures at debug level - Log endpoint_contact resolution failures - Log destination extraction failures at debug level Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- Interface/MeshCore_Dynamic_Interface.py | 54 ++++++++++++++++----- Interface/MeshCore_Interface.py | 62 ++++++++++++------------- 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/Interface/MeshCore_Dynamic_Interface.py b/Interface/MeshCore_Dynamic_Interface.py index 6c2ccbd..8a55547 100644 --- a/Interface/MeshCore_Dynamic_Interface.py +++ b/Interface/MeshCore_Dynamic_Interface.py @@ -548,8 +548,11 @@ async def _async_setup(self): await self._mc.commands.set_radio( self.radio_freq, self.radio_bw, self.radio_sf, self.radio_cr ) - except Exception: - pass + except Exception as exc: + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"Radio config error: {exc}", RNS.LOG_WARNING + ) try: secret_bytes = bytes.fromhex(self.channel_secret_hex) @@ -652,8 +655,12 @@ async def _bind_discovery_loop(self): f"{self.BIND_REQ_PREFIX}" f"{self._own_mc_key}:{self._own_capability()}" ) - except Exception: - pass + except Exception as exc: + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"Failed to send RNSBIND_REQ: {exc}", + RNS.LOG_WARNING + ) retries += 1 await asyncio.sleep(self.BIND_RESP_WINDOW_S) @@ -666,8 +673,12 @@ async def _bind_discovery_loop(self): f"{self.BIND_PREFIX}" f"{self._own_mc_key}:{self._own_capability()}" ) - except Exception: - pass + except Exception as exc: + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"Failed to send RNSBIND heartbeat: {exc}", + RNS.LOG_WARNING + ) await asyncio.sleep(self.BIND_HEARTBEAT_S) async def _delayed_bind_response(self): @@ -686,8 +697,12 @@ async def _delayed_bind_response(self): f"after {delay:.1f}s backoff.", RNS.LOG_DEBUG ) - except Exception: - pass + except Exception as exc: + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"Failed to send RNSBIND response: {exc}", + RNS.LOG_WARNING + ) # ------------------------------------------------------------------------- # Maintenance @@ -877,7 +892,13 @@ async def _process_tunnel_text(self, text: str, sender: str = "", rx_mode: str = b64 += "=" * (-len(b64) % 4) try: raw = base64.urlsafe_b64decode(b64) - except Exception: + except Exception as exc: + if self.debug_level == "debug": + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"base64 decode error: {exc}", + RNS.LOG_DEBUG + ) return if len(raw) < self.HEADER_SIZE: @@ -922,7 +943,12 @@ async def _process_tunnel_text(self, text: str, sender: str = "", rx_mode: str = ) del self._assembly[key] del self._assembly_meta[key] - except Exception: + except Exception as exc: + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"Reassembly failed for pkt_id={pkt_id} " + f"from '{sender}': {exc}", RNS.LOG_WARNING + ) self._assembly.pop(key, None) self._assembly_meta.pop(key, None) return @@ -1126,8 +1152,12 @@ def processOutgoing(self, data): try: # Thread-safe blocking put handles backpressure cleanly self._outqueue.put((mode, target, frag_str), block=True, timeout=None) - except Exception: - pass + except Exception as exc: + RNS.log( + f"MeshCore_Dynamic_Interface [{self.name}]: " + f"Failed to enqueue fragment: {exc}", + RNS.LOG_WARNING + ) self.txb += len(data) diff --git a/Interface/MeshCore_Interface.py b/Interface/MeshCore_Interface.py index c414d3d..235c53f 100644 --- a/Interface/MeshCore_Interface.py +++ b/Interface/MeshCore_Interface.py @@ -143,7 +143,8 @@ def _read_reticulum_config_file(self): cfg[k.strip()] = v.strip() if cfg: return cfg - except Exception: + except Exception as exc: + _safe_log(self._LOG_WARNING, f"MeshCore: failed to read config file {p}: {exc}") continue return None @@ -285,8 +286,8 @@ async def _on_rx_log(event): # map advert name lower() -> contact public key for quick resolution self.dest_to_node_dict[adv.lower()] = contact _safe_log(self._LOG_INFO, f"MeshCore: discovered {len(contacts)} contacts on device") - except Exception: - pass + except Exception as exc: + _safe_log(self._LOG_WARNING, f"MeshCore: initial contact fetch failed: {exc}") # Map endpoint_contact explicitly if configured if self.endpoint_contact: @@ -307,24 +308,20 @@ async def _on_rx_log(event): _safe_log(self._LOG_INFO, "MeshCoreInterface: online (meshcore ready)") # Register with RNS transport only once and only after online - try: - # RNS.Transport.register_interface(self) - use Interface.register? Use Transport global if available - if not self._registered_with_rns: - try: - # Preferred: RNS.Transport.register_interface - transport = getattr(RNS, "Transport", None) - if transport and hasattr(transport, "register_interface"): - transport.register_interface(self) - else: - # Fallback to Interface.register_interface if present - if hasattr(self, "register_interface"): - self.register_interface() - self._registered_with_rns = True - _safe_log(self._LOG_INFO, f"MeshCoreInterface: registered with Reticulum transport (name={self.name})") - except Exception as e: - _safe_log(self._LOG_WARNING, f"MeshCoreInterface: failed to register with Reticulum transport: {e}") - except Exception: - pass + if not self._registered_with_rns: + try: + # Preferred: RNS.Transport.register_interface + transport = getattr(RNS, "Transport", None) + if transport and hasattr(transport, "register_interface"): + transport.register_interface(self) + else: + # Fallback to Interface.register_interface if present + if hasattr(self, "register_interface"): + self.register_interface() + self._registered_with_rns = True + _safe_log(self._LOG_INFO, f"MeshCoreInterface: registered with Reticulum transport (name={self.name})") + except Exception as e: + _safe_log(self._LOG_WARNING, f"MeshCoreInterface: failed to register with Reticulum transport: {e}") return True @@ -332,9 +329,8 @@ async def _on_rx_log(event): try: fut.result(timeout=5) - except Exception: - # That's fine; _async_setup will complete asynchronously - pass + except Exception as exc: + _safe_log(self._LOG_DEBUG, f"MeshCore: async setup did not complete within 5s (will continue in background): {exc}") async def _handle_incoming_payload(self, event, payload): """ @@ -393,7 +389,8 @@ async def _handle_incoming_payload(self, event, payload): sender_hex = contact_obj.get("public_key") or contact_obj.get("pubkey") else: sender_hex = str(from_key) - except Exception: + except Exception as exc: + _safe_log(self._LOG_DEBUG, f"MeshCore: sender key normalization fallback: {exc}") sender_hex = str(from_key) # Normalize short prefixes to hex-like strings for dictionary keys @@ -412,8 +409,8 @@ async def _handle_incoming_payload(self, event, payload): if sender_hex and isinstance(sender_hex, str) and len(sender_hex) >= 8: # ensure a mapping exists for the sender prefix -> contact (use contact_obj if available) self.dest_to_node_dict[sender_hex[:8]] = contact_obj or sender_hex - except Exception: - pass + except Exception as exc: + _safe_log(self._LOG_DEBUG, f"MeshCore: peer mapping update failed: {exc}") # Debug: print raw metadata bytes for inspection try: @@ -513,10 +510,10 @@ async def _handle_new_contact_event(self, event): self.endpoint_contact = pk _safe_log(self._LOG_INFO, f"MeshCore: endpoint_contact resolved to {adv} ({pk[:12]}...)") break - except Exception: - pass - except Exception: - pass + except Exception as exc: + _safe_log(self._LOG_WARNING, f"MeshCore: endpoint_contact resolution failed: {exc}") + except Exception as exc: + _safe_log(self._LOG_WARNING, f"MeshCore: _handle_new_contact_event error: {exc}") def _payload_for_send(self, data: bytes) -> str: """ @@ -691,7 +688,8 @@ def process_outgoing(self, data: bytes): mapped = self.dest_to_node_dict.get(bytes(rns_dest).hex()) or self.dest_to_node_dict.get(bytes(rns_dest).hex()[:8]) if mapped: dest = mapped - except Exception: + except Exception as exc: + _safe_log(self._LOG_DEBUG, f"MeshCore: destination extraction failed: {exc}") dest = None # normalize dest to hex string if bytes