Summary
RibbonController.Engines is declared internal IAppItemEngines Engines => Globals.Engines; with no null guard on Globals, unlike its sibling properties SB and Triage in the same file which both use Globals?.. Any ribbon callback that reaches Engines before SetGlobals has run throws NullReferenceException.
Environment
- OS/version: Windows 11, Outlook desktop (VSTO add-in host)
- Runtime: .NET Framework 4.8.1, TaskMaster VSTO add-in
- Command/flags used: Outlook Explorer ribbon, Spam Manager and Triage configuration menus
- Data source or fixture: Live Outlook profile during add-in startup
Steps to Reproduce
- Reload the TaskMaster add-in so the ribbon is constructed before the controller's
Globals is assigned.
- Invoke any callback that routes through
RibbonController.Engines - TestSpam_Click, SpamBayesEnabled_Click, SpamBayesEnabled_GetPressed, SpamSaveNetwork_Click, SpamSaveLocal_Click, GetSaveLocation_Click, TriageEnabled_Click, TriageEnabled_GetPressed, TriageSaveNetwork_Click, TriageSaveLocal_Click, or TriageGetSaveLocation_Click.
- Observe the
NullReferenceException.
Expected Behavior
Engines behaves like its siblings and returns null rather than throwing when Globals has not yet been assigned, so callers can guard. The sibling precedent is already in the same file:
return Globals?.Engines?.InboxEngines?.TryGetValue("Spam", out var engine) ?? false
? engine as SpamBayes
: null;
Actual Behavior
internal IAppItemEngines Engines => Globals.Engines;
(TaskMaster/Ribbon/RibbonController.Intelligence.cs, Spam Manager region.)
Globals is unguarded, so the property throws instead of returning null.
Logs / Screenshots
System.NullReferenceException: Object reference not set to an instance of an object.
at TaskMaster.RibbonController.get_Engines()
Impact / Severity
The reachable window is narrower than the one in issue #503 (it requires the callback to run before SetGlobals rather than merely before InitAsync), and the affected callbacks are in configuration submenus rather than primary commands. It is nevertheless a real inconsistency with the sibling properties and an avoidable throw.
Source
From: docs/features/potential/2026-08-08-ribbon-controller-engines-null-unsafe.md
Summary
RibbonController.Enginesis declaredinternal IAppItemEngines Engines => Globals.Engines;with no null guard onGlobals, unlike its sibling propertiesSBandTriagein the same file which both useGlobals?.. Any ribbon callback that reachesEnginesbeforeSetGlobalshas run throwsNullReferenceException.Environment
Steps to Reproduce
Globalsis assigned.RibbonController.Engines-TestSpam_Click,SpamBayesEnabled_Click,SpamBayesEnabled_GetPressed,SpamSaveNetwork_Click,SpamSaveLocal_Click,GetSaveLocation_Click,TriageEnabled_Click,TriageEnabled_GetPressed,TriageSaveNetwork_Click,TriageSaveLocal_Click, orTriageGetSaveLocation_Click.NullReferenceException.Expected Behavior
Enginesbehaves like its siblings and returnsnullrather than throwing whenGlobalshas not yet been assigned, so callers can guard. The sibling precedent is already in the same file:Actual Behavior
(
TaskMaster/Ribbon/RibbonController.Intelligence.cs, Spam Manager region.)Globalsis unguarded, so the property throws instead of returningnull.Logs / Screenshots
Impact / Severity
The reachable window is narrower than the one in issue #503 (it requires the callback to run before
SetGlobalsrather than merely beforeInitAsync), and the affected callbacks are in configuration submenus rather than primary commands. It is nevertheless a real inconsistency with the sibling properties and an avoidable throw.Source
From: docs/features/potential/2026-08-08-ribbon-controller-engines-null-unsafe.md