You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Many collectors and live queries depend on permissions (and platform features) that a monitoring login may not have — most notably VIEW DATABASE STATE on Azure SQL DB, which every sys.dm_os_* DMV requires. When a login lacks the permission, the affected query throws and the data silently doesn't populate. The user sees empty tabs/columns with no indication of why, and often can't tell "there's no data yet" from "your login can't read this."
This surfaced concretely in #1535: the connectivity probe (fixed) and the FinOps live inventory (fixed separately) both coupled SERVERPROPERTY('EngineEdition') to sys.dm_os_sys_info, so a permission-starved Azure login lost the whole result.
Scope of the audit
Catalog every collector + live query's permission/platform requirements. For each: which DMV/catalog/feature it needs, what permission that requires (VIEW DATABASE STATE, VIEW SERVER STATE, VIEW DATABASE PERFORMANCE STATE, msdb access, ALTER ANY EVENT SESSION, etc.), and which platforms it applies to (on-prem / Azure SQL DB / MI / RDS).
Known instance to fold in: PerformanceMonitor.Collectors/ServerPropertiesCollector.cs selects SERVERPROPERTY('EngineEdition') in the same query as FROM sys.dm_os_sys_info (lines ~119/151/170). A login without VIEW DATABASE STATE fails to collect server properties at all (not just the hardware columns). Same class as the [QUESTION] About deadlocks, generic webhook #1535 display-query fix, but on the collection path (Lite + Darling).
Surface WHY a tab/column is empty, not just log it. When a collector/query fails on a permission (or a platform doesn't support a feature), record a structured reason and show it in the affected UI — a per-tab/per-section note ("Requires VIEW DATABASE STATE on this database" / "Not available on Azure SQL DB"), so the operator can distinguish a permission gap from no-data-yet and knows exactly what to grant. Today the FinOps tabs only AppLogger.Error(...).
Decouple permission-free facts from permission-gated ones where a single query mixes them (the [QUESTION] About deadlocks, generic webhook #1535 pattern) so a partial-permission login still gets what it's entitled to.
Document the required grants per platform in the README (the immediate VIEW DATABASE STATE doc lands with the [QUESTION] About deadlocks, generic webhook #1535 FinOps fix; this audit generalizes it into a full matrix).
Value
Turns a class of silent "empty tab, no idea why" support issues into a self-service "grant X to see Y" experience, across Lite / Dashboard / Darling. Larger than any one fix — filing so it's tracked as its own initiative.
Audit note: I started the ServerPropertiesCollector decoupling this issue names, then backed out. It is not the ~15-line mechanical change it looks like, and the reason is worth recording before someone else picks it up.
The defect is real and confirmed
PerformanceMonitor.Collectors/ServerPropertiesCollector.cs mixes permission-free SERVERPROPERTY scalars with FROM sys.dm_os_sys_info AS osi (:151) in one SELECT with no TRY/CATCH. A login without VIEW DATABASE STATE loses the entireserver_properties row, in both Lite and Darling — not just the hardware columns.
The fix pattern does sit ten lines below, at :162-174, where the supplemental health query wraps its own dm_os_sys_info read so LPIM degrades to NULL instead of killing the batch.
Why it is not mechanical
Wrapping the DMV read means those six values can now be absent, and the consuming code is not built for that:
ServerPropertiesCollector.cs:40-42 declares int CpuCount, int HyperthreadRatio, long PhysicalMemoryMb — non-nullable.
Making them nullable ripples outward: the MCP JSON contract (DarlingMcpDataTools.cs:727-731) and viewer arithmetic (Darling/.../FinOpsTab.Loaders.cs:260, :275-276, :281, :311, which divide by and format PhysicalMemoryMb), plus the Lite equivalents and the stored column definitions.
The decision it needs
When hardware is unreadable, what gets stored?
NULL — honest, but a nullability change through both apps' Row type, MCP output shape, UI arithmetic, and possibly the DuckDB/Postgres column definitions.
Zero sentinel — no downstream change at all, and the viewer already guards PhysicalMemoryMb > 0, so the plumbing is arguably there. But it stores a number that is not true.
Split rows — collect the permission-free properties always, hardware separately.
Option 2 is by far the cheapest and option 1 is the most correct; that is a product call, not a cleanup. Pairing whichever wins with the existing HardwareUnavailableReason surfacing (already in Lite at LocalDataService.FinOps.ServerProperties.cs:181-183, and missing from the Darling viewer — a parity gap in its own right) is what would make this issue's "surface WHY" half real rather than reactive.
Closing as delivered: the audit surfacing this issue asked for shipped across four PRs - #1663 (a missing DMV grant no longer loses the whole server_properties row), #1678 (the Darling viewer's Server Inventory explains missing hardware instead of showing blanks), #1679 (permission-denied collectors surfaced + the platform matrix documented), and #1732 (database_size_stats stops touching master on Azure SQL DB; error 300 explains itself). The one remaining slice is the ServerPropertiesCollector decoupling, and the comment above stands as the record of why it is not the mechanical change it looks like - whoever picks it up should start from that note, in a fresh focused issue.
Activity
erikdarlingdata commentedon Jul 25, 2026
Audit note: I started the
ServerPropertiesCollectordecoupling this issue names, then backed out. It is not the ~15-line mechanical change it looks like, and the reason is worth recording before someone else picks it up.The defect is real and confirmed
PerformanceMonitor.Collectors/ServerPropertiesCollector.csmixes permission-freeSERVERPROPERTYscalars withFROM sys.dm_os_sys_info AS osi(:151) in one SELECT with no TRY/CATCH. A login withoutVIEW DATABASE STATEloses the entireserver_propertiesrow, in both Lite and Darling — not just the hardware columns.The fix pattern does sit ten lines below, at :162-174, where the supplemental health query wraps its own
dm_os_sys_inforead so LPIM degrades to NULL instead of killing the batch.Why it is not mechanical
Wrapping the DMV read means those six values can now be absent, and the consuming code is not built for that:
ServerPropertiesCollector.cs:40-42declaresint CpuCount,int HyperthreadRatio,long PhysicalMemoryMb— non-nullable.reader.GetInt32(6),GetInt32(7),GetInt64(8)at :307-309.GetInt32onDBNullthrowsInvalidCastException— the same failure class as Full Dashboard (deprecated): Trace Flag Changes grid throws InvalidCastException now that the view returns rows #1660, just relocated.DarlingMcpDataTools.cs:727-731) and viewer arithmetic (Darling/.../FinOpsTab.Loaders.cs:260,:275-276,:281,:311, which divide by and formatPhysicalMemoryMb), plus the Lite equivalents and the stored column definitions.The decision it needs
When hardware is unreadable, what gets stored?
PhysicalMemoryMb > 0, so the plumbing is arguably there. But it stores a number that is not true.Option 2 is by far the cheapest and option 1 is the most correct; that is a product call, not a cleanup. Pairing whichever wins with the existing
HardwareUnavailableReasonsurfacing (already in Lite atLocalDataService.FinOps.ServerProperties.cs:181-183, and missing from the Darling viewer — a parity gap in its own right) is what would make this issue's "surface WHY" half real rather than reactive.Merge pull request #1663 from erikdarlingdata/feature/1591-decouple-p…
Stop losing the whole server_properties row on a missing DMV grant (e…
Badge permission-denied collectors on the Collection Health tab (#1591)
Merge pull request #1678 from erikdarlingdata/feature/1591-darling-ha…
Merge pull request #1679 from erikdarlingdata/feature/1591-surface-pe…
erikdarlingdata commentedon Jul 28, 2026
Closing as delivered: the audit surfacing this issue asked for shipped across four PRs - #1663 (a missing DMV grant no longer loses the whole server_properties row), #1678 (the Darling viewer's Server Inventory explains missing hardware instead of showing blanks), #1679 (permission-denied collectors surfaced + the platform matrix documented), and #1732 (database_size_stats stops touching master on Azure SQL DB; error 300 explains itself). The one remaining slice is the ServerPropertiesCollector decoupling, and the comment above stands as the record of why it is not the mechanical change it looks like - whoever picks it up should start from that note, in a fresh focused issue.
Explain missing hardware in the Darling viewer's Server Inventory (er…
Document which collectors run on which platform (erikdarlingdata#1591)
Read the Azure sibling rows the size collector deliberately emits (er…