From 325ac4d04f80b9e94d7d6147e5f33655c90cb106 Mon Sep 17 00:00:00 2001 From: Erik Meyer Date: Mon, 31 Aug 2026 11:02:39 -0400 Subject: [PATCH] fix: surface masked device/room construction failures GetDevice returns null for both a genuinely unknown type and a registered type whose factory throws/returns null, so LoadDevices/LoadRooms logged a misleading 'unknown type' message (at Information level for devices) even when the type was known but failed to construct - e.g. a duplicate-feedback ArgumentException from a plugin constructor. Add DeviceFactory.HasFactoryForType so the callers can distinguish the two: a registered-but-failed type now logs an Error pointing at the exception already logged by GetDevice; a genuinely unknown type keeps the 'unknown type' message (now Warning). No change to exception flow. --- .../Factory/DeviceFactory.cs | 13 +++++++++++++ src/PepperDash.Essentials/ControlSystem.cs | 9 +++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs index 74796da1..e28add37 100644 --- a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs @@ -267,4 +267,17 @@ public class DeviceFactory ? FactoryMethods : FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value); } + + /// + /// Indicates whether a factory is registered for the specified device type name. + /// + /// Lets callers of distinguish a genuinely unknown device type from a + /// known type whose factory failed to build the device (both currently return from + /// ), so the two can be logged with accurate, distinct messages. + /// The device type name to check. Matching is case-insensitive. + /// if a factory is registered for ; otherwise . + public static bool HasFactoryForType(string typeName) + { + return !string.IsNullOrEmpty(typeName) && FactoryMethods.ContainsKey(typeName); + } } diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs index 701a0ec4..4e853a1d 100644 --- a/src/PepperDash.Essentials/ControlSystem.cs +++ b/src/PepperDash.Essentials/ControlSystem.cs @@ -556,8 +556,10 @@ public class ControlSystem : CrestronControlSystem, ILoadConfig, IInitialization if (newDev != null) DeviceManager.AddDevice(newDev); + else if (Core.DeviceFactory.HasFactoryForType(devConf.Type)) + Debug.LogMessage(LogEventLevel.Error, "ERROR: Device type '{deviceType:l}' is registered but failed to build device '{deviceKey:l}' (factory returned null; see any exception logged above for the cause).", devConf.Type, devConf.Key); else - Debug.LogMessage(LogEventLevel.Information, "ERROR: Cannot load unknown device type '{deviceType:l}', key '{deviceKey:l}'.", devConf.Type, devConf.Key); + Debug.LogMessage(LogEventLevel.Warning, "ERROR: Cannot load unknown device type '{deviceType:l}', key '{deviceKey:l}'.", devConf.Type, devConf.Key); } catch (Exception e) { @@ -904,7 +906,10 @@ public class ControlSystem : CrestronControlSystem, ILoadConfig, IInitialization if (room == null) { - Debug.LogWarning("ERROR: Cannot load unknown room type '{roomType:l}', key '{roomKey:l}'.", roomConfig.Type, roomConfig.Key); + if (Core.DeviceFactory.HasFactoryForType(roomConfig.Type)) + Debug.LogError("ERROR: Room type '{roomType:l}' is registered but failed to build room '{roomKey:l}' (factory returned null; see any exception logged above for the cause).", roomConfig.Type, roomConfig.Key); + else + Debug.LogWarning("ERROR: Cannot load unknown room type '{roomType:l}', key '{roomKey:l}'.", roomConfig.Type, roomConfig.Key); continue; }