Skip to content

[Power BI] Address ARG payload size errors#1849

Draft
Copilot wants to merge 8 commits intodevfrom
copilot/fix-governance-report-loading
Draft

[Power BI] Address ARG payload size errors#1849
Copilot wants to merge 8 commits intodevfrom
copilot/fix-governance-report-loading

Conversation

Copy link
Contributor

Copilot AI commented Oct 10, 2025

Problem

Users with large Azure environments are encountering payload size limit errors when attempting to load the Governance and Workload Optimization Power BI reports. The error message appears as:

Response payload size is 48439993, and has exceeded the limit of 16777216. Please consider querying less data at a time and make paginated call if needed.

Error screenshot showing 15 queries blocked by payload size limit

This occurs because both reports use Azure Resource Graph queries with [resultTruncated = false] to retrieve comprehensive resource details. For organizations with millions of resources, the response payload exceeds Azure Resource Graph's 16 MB limit, preventing the reports from loading.

Root Cause

Azure Resource Graph enforces a 16 MB (16,777,216 bytes) response payload limit per query. The Governance and Workload Optimization reports are designed to show detailed resource-level information and are optimized for small to medium-sized environments. When used in large enterprise environments with millions of resources, the unfiltered queries exceed this limit.

This is a by-design limitation of Azure Resource Graph, not a bug in the FinOps toolkit.

Solution

This PR provides comprehensive documentation and practical guidance to help users understand and mitigate the payload size limit error. Since this is a platform limitation, the solution focuses on empowering users with actionable workarounds.

Changes Made

1. Enhanced Error Documentation (help/errors.md)

Expanded the existing "Response payload size exceeded" error section with detailed, step-by-step mitigation strategies:

Option 1: Filter by Subscription

| where subscriptionId in~ ('subscription-id-1', 'subscription-id-2')

Option 2: Filter by Tags

| where tags.Environment in~ ('Production', 'Staging')
| where tags.CostCenter == '12345' and tags.Environment =~ 'Production'

Option 3: Remove Unnecessary Columns

  • Guidance on identifying and removing columns that aren't used in report visuals

Option 4: Disable Problematic Queries

  • Instructions for disabling specific failing queries while keeping others functional

Each option includes:

  • Clear step-by-step instructions for implementing the solution in Power Query Editor
  • KQL code examples with proper syntax
  • Explanations of when to use each approach
  • Links to official Microsoft documentation

2. Updated Report Documentation

Added "Known limitations" sections to both affected reports:

  • Governance report (power-bi/governance.md)
  • Workload Optimization report (power-bi/workload-optimization.md)

These sections:

  • Explain the 16 MB Azure Resource Graph payload limit
  • Clarify that reports are designed for small to medium-sized environments
  • Provide quick summary of mitigation options
  • Link to detailed error reference guide

3. Changelog Entry

Added documentation improvements to the Unreleased section of changelog.md, following the repository's documentation standards.

Impact

  • No code changes - Documentation only, zero risk of introducing bugs
  • No breaking changes - All existing functionality preserved
  • Improved user experience - Clear, actionable self-service guidance
  • Reduced support burden - Users can resolve issues independently
  • Proactive education - Users understand limitations before encountering errors
  • Consistent guidance - Aligned with official Microsoft Azure Resource Graph documentation

References

This documentation is based on and links to official Microsoft documentation:

Testing

  • Verified all documentation links are valid
  • Confirmed markdown formatting follows repository standards
  • Validated KQL syntax examples against Azure Resource Graph documentation
  • Ensured consistency between Governance and Workload Optimization report documentation
  • Tested that solutions are practical and align with Microsoft best practices

Future Enhancements (Out of Scope)

Potential product improvements to consider in future releases:

  1. Add subscription/tag filter parameters directly to report templates
  2. Implement pagination for large datasets
  3. Provide aggregated summary views for enterprise environments
  4. Optimize default queries to select only required columns
  5. Add environment size detection during report setup

Fixes: Provides mitigation guidance for the Governance Report payload size limit error reported in the issue.

Original prompt

This section details on the original issue you should resolve

<issue_title>Governance Report is not loading says payload size limit is exceeding the limits.</issue_title>
<issue_description><!--
⚠️⚠️⚠️ BEFORE YOU SUBMIT ⚠️⚠️⚠️

  1. Confirm there isn't an issue already. If so, vote it up (👍) and add comments.
  2. Complete all TODO items below and remove the TODO lines after.
  3. Internal: Add applicable labels: Type, Micro PR, Area
    -->

🐛 Problem

TODO: Governance report is not loading - With payload size limits exceeding the limits. Currently using V0.11 version of Finops hub. MCA customer with billing account admin privileges is trying to pull out data in the governance report, below is the error reported.

👣 Repro steps

TODO: Add repro steps below:

  1. Go to Governance.Pbit
  2. Click on Load
  3. See error

🤔 Expected

TODO: All the ADF pipelines are successful and remaining cost summary, workload optimization reports are loading ok., where-as governance report is not at all loading at this moment.

📷 Screenshots

TODO: Attached is the screenshot.

Image

ℹ️ Additional context

TODO: Governance Reports fails to load in the customer environment due to payload size limits issue.

🙋‍♀️ Ask for the community

We could use your help:

  1. Please vote this issue up (👍) to prioritize it.
  2. Leave comments to help us solidify the vision.
    </issue_description>

<agent_instructions>Triage the issue, research using mslearn, provide proposed solutions along with links/citations to authorative sources.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

Fixes #1768


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits October 10, 2025 20:34
Co-authored-by: MSBrett <24294904+MSBrett@users.noreply.github.com>
Co-authored-by: MSBrett <24294904+MSBrett@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix governance report loading issue due to payload size limit Add comprehensive documentation for Azure Resource Graph payload size limit errors in Governance and Workload Optimization reports Oct 10, 2025
Copilot AI requested a review from MSBrett October 10, 2025 20:38
@flanakin flanakin added this to the v14 milestone Jan 6, 2026
@flanakin flanakin modified the milestones: v14, v15 Feb 23, 2026
Copy link
Collaborator

@flanakin flanakin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] PR Review

Summary: This documentation-only PR adds helpful mitigation guidance for Azure Resource Graph payload size limit errors. The expanded error documentation is a significant improvement. A couple of items to address before merging.

⚠️ Should fix (1)

  1. Changelog entries are placed under "Implementing FinOps guide v14" but these are Power BI report documentation changes. They should be in their own section (e.g., a new ### [Power BI reports](power-bi/reports.md) v14 section or a standalone ### Documentation improvements section). Entries also missing issue link #1768.

💡 Suggestions (1)

  1. "small- and medium-sized" uses a suspended hyphen that's grammatically correct but unusual in Microsoft docs — consider "small and medium-sized" for readability.

@flanakin flanakin requested a review from Copilot March 11, 2026 16:01
@flanakin flanakin changed the title Add comprehensive documentation for Azure Resource Graph payload size limit errors in Governance and Workload Optimization reports [Power BI] Address ARG payload size errors Mar 11, 2026
@flanakin flanakin added Tool: Power BI Power BI reports and removed Skill: Documentation Documentation updates Skill: DevOps GitHub setup and automation Tool: FinOps guide Implementing FinOps guide labels Mar 11, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses Azure Resource Graph (ARG) response payload size limit failures affecting the Governance and Workload optimization Power BI reports by adding end-user troubleshooting guidance and introducing subscription-batched ARG querying in the shared dataset definitions.

Changes:

  • Added ftk_ARGBatchSize / ftk_QueryARG and updated multiple ARG-backed tables to query in subscription batches.
  • Documented the 16 MB ARG payload limit and mitigation steps in the error reference and report docs.
  • Added a changelog entry under v14 for the Power BI report mitigation.

Reviewed changes

Copilot reviewed 30 out of 43 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/power-bi/storage/Shared.Dataset/definition/tables/VirtualMachines.tmdl Storage dataset VirtualMachines definition updated/redirected to support subscription-batched ARG querying.
src/power-bi/storage/Shared.Dataset/definition/tables/Subscriptions.tmdl Storage dataset Subscriptions definition updated/redirected (supports new batching approach).
src/power-bi/storage/Shared.Dataset/definition/tables/SqlDatabases.tmdl Storage dataset SqlDatabases definition updated/redirected to use batched ARG querying.
src/power-bi/storage/Shared.Dataset/definition/tables/Resources.tmdl Storage dataset Resources definition updated/redirected to use batched ARG querying.
src/power-bi/storage/Shared.Dataset/definition/tables/PublicIPAddresses.tmdl Storage dataset PublicIPAddresses definition updated/redirected to use batched ARG querying.
src/power-bi/storage/Shared.Dataset/definition/tables/PolicyStates.tmdl Storage dataset PolicyStates definition updated/redirected to support batching (subscriptionId derivation).
src/power-bi/storage/Shared.Dataset/definition/tables/PolicyAssignments.tmdl Storage dataset PolicyAssignments definition updated/redirected to support batching (subscriptionId derivation).
src/power-bi/storage/Shared.Dataset/definition/tables/NetworkSecurityGroups.tmdl Storage dataset NSG definition updated/redirected to use batched querying.
src/power-bi/storage/Shared.Dataset/definition/tables/NetworkInterfaces.tmdl Storage dataset NIC definition updated/redirected to use batched querying.
src/power-bi/storage/Shared.Dataset/definition/tables/ManagementGroups.tmdl Storage dataset ManagementGroups definition updated/redirected (context for governance reporting).
src/power-bi/storage/Shared.Dataset/definition/tables/Disks.tmdl Storage dataset Disks definition updated/redirected to use batched ARG querying.
src/power-bi/storage/Shared.Dataset/definition/tables/AdvisorReservationRecommendations.tmdl Storage dataset AdvisorReservationRecommendations updated/redirected (aligns with batching refactor).
src/power-bi/storage/Shared.Dataset/definition/tables/AdvisorRecommendations.tmdl Storage dataset AdvisorRecommendations updated/redirected to use batched ARG querying.
src/power-bi/storage/Shared.Dataset/definition/expressions.tmdl Adds ftk_ARGBatchSize and ftk_QueryARG batching helper functions (storage dataset).
src/power-bi/kql/Shared.Dataset/definition/tables/VirtualMachines.tmdl KQL dataset VirtualMachines now uses ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/SqlDatabases.tmdl KQL dataset SqlDatabases now uses ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/Resources.tmdl KQL dataset Resources now uses ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/PublicIPAddresses.tmdl KQL dataset PublicIPAddresses now uses ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/PolicyStates.tmdl KQL dataset PolicyStates derives subscriptionId and uses ftk_QueryARG.
src/power-bi/kql/Shared.Dataset/definition/tables/PolicyAssignments.tmdl KQL dataset PolicyAssignments derives subscriptionId and uses ftk_QueryARG.
src/power-bi/kql/Shared.Dataset/definition/tables/NetworkSecurityGroups.tmdl KQL dataset NSGs now use ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/NetworkInterfaces.tmdl KQL dataset NICs now use ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/Disks.tmdl KQL dataset Disks now use ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/tables/AdvisorReservationRecommendations.tmdl KQL dataset AdvisorReservationRecommendations updated and moved to batched querying.
src/power-bi/kql/Shared.Dataset/definition/tables/AdvisorRecommendations.tmdl KQL dataset AdvisorRecommendations now uses ftk_QueryARG batching.
src/power-bi/kql/Shared.Dataset/definition/expressions.tmdl Adds ftk_ARGBatchSize and ftk_QueryARG batching helper functions (KQL dataset).
docs-mslearn/toolkit/power-bi/workload-optimization.md Adds a “Known limitations” section referencing ARG payload limits and ftk_ARGBatchSize.
docs-mslearn/toolkit/power-bi/governance.md Adds a “Known limitations” section referencing ARG payload limits and ftk_ARGBatchSize.
docs-mslearn/toolkit/help/errors.md Expands troubleshooting for “Response payload size exceeded…” with mitigation options and batching guidance.
docs-mslearn/toolkit/changelog.md Adds v14 Power BI reports entry documenting the ARG batching mitigation.

Comment on lines +512 to +520
batchSize = ftk_ARGBatchSize() * (if batchMultiplier <> null then batchMultiplier else 1),
subQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId" & ftk_DemoFilter(),
Subscriptions = AzureResourceGraph.Query(subQuery, "Tenant", null, null, [resultTruncated = false]),
SubscriptionIds = Subscriptions[subscriptionId],
BatchCount = Number.RoundUp(List.Count(SubscriptionIds) / batchSize),
Batches = List.Transform({0..BatchCount-1}, each
let
batchStart = _ * batchSize,
batchIds = List.Range(SubscriptionIds, batchStart, List.Min({batchSize, List.Count(SubscriptionIds) - batchStart})),
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ftk_QueryARG computes batchSize directly from ftk_ARGBatchSize and uses it in division and List.Range indexing. If a user sets ftk_ARGBatchSize() to 0 or a non-integer value, this can cause division-by-zero or type conversion failures at runtime. Consider clamping/validating to an integer >= 1 (and optionally surfacing a clearer error message).

Copilot uses AI. Check for mistakes.
| where type == 'microsoft.advisor/recommendations'
| where properties['category'] == 'Cost'
| where properties['shortDescription']['solution'] == 'Consider virtual machine reserved instance to save over your on-demand costs'
| where properties.category == 'Cost'
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This query is for AdvisorReservationRecommendations but it no longer filters to reservation/RI-specific recommendations (it currently pulls all Cost-category advisor recommendations). That will likely duplicate data already in AdvisorRecommendations and can change report results. Consider restoring a reservation-specific predicate (for example based on recommendationTypeId / reservedResourceType / a known solution string) so the table matches its intent.

Suggested change
| where properties.category == 'Cost'
| where properties.category == 'Cost'
| where isnotempty(tostring(properties.extendedProperties.reservedResourceType))

Copilot uses AI. Check for mistakes.
if Source = null then
#table(
{ "id", "name", "properties.recommendationTypeId", "properties.shortDescription", "properties.resourceMetadata", "properties.suppressionIds", "properties.impactedField", "properties.impactedValue", "properties.lastUpdated", "properties.category", "properties.metadata", "properties.impact", "properties.shortDescription.problem", "properties.shortDescription.solution", "properties.extendedProperties.reservedResourceType", "properties.extendedProperties.annualSavingsAmount", "properties.extendedProperties.targetResourceCount", "properties.extendedProperties.savingsCurrency", "properties.extendedProperties.lookbackPeriod", "properties.extendedProperties.savingsAmount", "properties.extendedProperties.displaySKU", "properties.extendedProperties.displayQty", "properties.extendedProperties.location", "properties.extendedProperties.region", "properties.extendedProperties.vmSize", "properties.extendedProperties.subId", "properties.extendedProperties.scope", "properties.extendedProperties.term", "properties.extendedProperties.sku", "properties.extendedProperties.qty", "properties.resourceMetadata.resourceId", "properties.resourceMetadata.singular", "properties.resourceMetadata.plural", "properties.resourceMetadata.action", "properties.resourceMetadata.source", "recommendedActions" },
{ "id", "name", "properties.recommendationTypeId", "properties.shortDescription", "properties.resourceMetadata", "properties.suppressionIds", "properties.impactedField", "properties.impactedValue", "properties.lastUpdated", "properties.category", "properties.metadata", "properties.impact", "properties.shortDescription.problem", "properties.shortDescription.solution", "properties.extendedProperties.ObservationPeriodStartDate", "properties.extendedProperties.ObservationPeriodEndDate", "properties.extendedProperties.reservedResourceType", "properties.extendedProperties.annualSavingsAmount", "properties.extendedProperties.targetResourceCount", "properties.extendedProperties.HasRecommendation", "properties.extendedProperties.savingsCurrency", "properties.extendedProperties.IsInReplication", "properties.extendedProperties.Recommended_DTU", "properties.extendedProperties.Recommended_SKU", "properties.extendedProperties.ResourceGroup", "properties.extendedProperties.lookbackPeriod", "properties.extendedProperties.savingsAmount", "properties.extendedProperties.DatabaseSize", "properties.extendedProperties.DatabaseName", "properties.extendedProperties.ServerName", "properties.extendedProperties.Region", "properties.extendedProperties.displaySKU", "properties.extendedProperties.displayQty", "properties.extendedProperties.location", "properties.extendedProperties.region", "properties.extendedProperties.vmSize", "properties.extendedProperties.subId", "properties.extendedProperties.scope", "properties.extendedProperties.term", "properties.extendedProperties.sku", "properties.extendedProperties.qty", "properties.extendedProperties.commitment", "properties.extendedProperties.currentSku", "properties.extendedProperties.targetSku", "properties.extendedProperties.recommendationMessage", "properties.resourceMetadata.resourceId", "properties.resourceMetadata.singular", "properties.resourceMetadata.plural", "properties.resourceMetadata.action", "properties.resourceMetadata.source", "recommendedActions", "SortOrder" },
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NullHandling creates an empty schema that doesn't include subscriptionId, but ftk_QueryARG appends a where subscriptionId in (...) filter and the underlying advisorresources rows will typically include subscriptionId. If there are no recommendations (Source = null), the returned schema will differ from the non-empty case, which can cause refresh/schema errors. Consider explicitly projecting the expected columns (including subscriptionId if needed) and making the empty #table schema match.

Suggested change
{ "id", "name", "properties.recommendationTypeId", "properties.shortDescription", "properties.resourceMetadata", "properties.suppressionIds", "properties.impactedField", "properties.impactedValue", "properties.lastUpdated", "properties.category", "properties.metadata", "properties.impact", "properties.shortDescription.problem", "properties.shortDescription.solution", "properties.extendedProperties.ObservationPeriodStartDate", "properties.extendedProperties.ObservationPeriodEndDate", "properties.extendedProperties.reservedResourceType", "properties.extendedProperties.annualSavingsAmount", "properties.extendedProperties.targetResourceCount", "properties.extendedProperties.HasRecommendation", "properties.extendedProperties.savingsCurrency", "properties.extendedProperties.IsInReplication", "properties.extendedProperties.Recommended_DTU", "properties.extendedProperties.Recommended_SKU", "properties.extendedProperties.ResourceGroup", "properties.extendedProperties.lookbackPeriod", "properties.extendedProperties.savingsAmount", "properties.extendedProperties.DatabaseSize", "properties.extendedProperties.DatabaseName", "properties.extendedProperties.ServerName", "properties.extendedProperties.Region", "properties.extendedProperties.displaySKU", "properties.extendedProperties.displayQty", "properties.extendedProperties.location", "properties.extendedProperties.region", "properties.extendedProperties.vmSize", "properties.extendedProperties.subId", "properties.extendedProperties.scope", "properties.extendedProperties.term", "properties.extendedProperties.sku", "properties.extendedProperties.qty", "properties.extendedProperties.commitment", "properties.extendedProperties.currentSku", "properties.extendedProperties.targetSku", "properties.extendedProperties.recommendationMessage", "properties.resourceMetadata.resourceId", "properties.resourceMetadata.singular", "properties.resourceMetadata.plural", "properties.resourceMetadata.action", "properties.resourceMetadata.source", "recommendedActions", "SortOrder" },
{ "id", "name", "subscriptionId", "properties.recommendationTypeId", "properties.shortDescription", "properties.resourceMetadata", "properties.suppressionIds", "properties.impactedField", "properties.impactedValue", "properties.lastUpdated", "properties.category", "properties.metadata", "properties.impact", "properties.shortDescription.problem", "properties.shortDescription.solution", "properties.extendedProperties.ObservationPeriodStartDate", "properties.extendedProperties.ObservationPeriodEndDate", "properties.extendedProperties.reservedResourceType", "properties.extendedProperties.annualSavingsAmount", "properties.extendedProperties.targetResourceCount", "properties.extendedProperties.HasRecommendation", "properties.extendedProperties.savingsCurrency", "properties.extendedProperties.IsInReplication", "properties.extendedProperties.Recommended_DTU", "properties.extendedProperties.Recommended_SKU", "properties.extendedProperties.ResourceGroup", "properties.extendedProperties.lookbackPeriod", "properties.extendedProperties.savingsAmount", "properties.extendedProperties.DatabaseSize", "properties.extendedProperties.DatabaseName", "properties.extendedProperties.ServerName", "properties.extendedProperties.Region", "properties.extendedProperties.displaySKU", "properties.extendedProperties.displayQty", "properties.extendedProperties.location", "properties.extendedProperties.region", "properties.extendedProperties.vmSize", "properties.extendedProperties.subId", "properties.extendedProperties.scope", "properties.extendedProperties.term", "properties.extendedProperties.sku", "properties.extendedProperties.qty", "properties.extendedProperties.commitment", "properties.extendedProperties.currentSku", "properties.extendedProperties.targetSku", "properties.extendedProperties.recommendationMessage", "properties.resourceMetadata.resourceId", "properties.resourceMetadata.singular", "properties.resourceMetadata.plural", "properties.resourceMetadata.action", "properties.resourceMetadata.source", "recommendedActions", "SortOrder" },

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +76
### [Power BI reports](power-bi/reports.md) v14

- **Fixed**
- Paginate Azure Resource Graph queries by subscription to mitigate [payload size limit](help/errors.md#response-payload-size-is-and-has-exceeded-the-limit) errors in the [Governance](power-bi/governance.md) and [Workload optimization](power-bi/workload-optimization.md) reports ([#1768](https://github.com/microsoft/finops-toolkit/issues/1768)).
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description states this is documentation-only / no code changes, but this changelog entry (and the accompanying .tmdl changes) indicate functional report query changes (ARG batching/pagination). Please update the PR description to reflect the code changes and include any validation/testing done for the updated Power Query logic.

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +121
batchSize = ftk_ARGBatchSize() * (if batchMultiplier <> null then batchMultiplier else 1),
subQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId" & ftk_DemoFilter(),
Subscriptions = AzureResourceGraph.Query(subQuery, "Tenant", null, null, [resultTruncated = false]),
SubscriptionIds = Subscriptions[subscriptionId],
BatchCount = Number.RoundUp(List.Count(SubscriptionIds) / batchSize),
Batches = List.Transform({0..BatchCount-1}, each
let
batchStart = _ * batchSize,
batchIds = List.Range(SubscriptionIds, batchStart, List.Min({batchSize, List.Count(SubscriptionIds) - batchStart})),
subFilter = " | where subscriptionId in (" & Text.Combine(List.Transform(batchIds, each "'" & _ & "'"), ",") & ")",
fullQuery = query & subFilter,
Source = AzureResourceGraph.Query(fullQuery, "Tenant", null, null, [resultTruncated = false])
in
if Table.HasColumns(Source, "Results") and Table.RowCount(Source) = 1 then null else Source
),
Filtered = List.RemoveNulls(Batches),
Combined = if List.Count(Filtered) > 0 then Table.Combine(Filtered) else null
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ftk_QueryARG assumes the subscription list query always returns a table with a [subscriptionId] column. If AzureResourceGraph.Query returns the single-row "Results" shape (for example, due to lack of permissions or transient failures), Subscriptions[subscriptionId] will throw and block all report queries. Consider applying the same null/empty-table handling used elsewhere before indexing the column (and short-circuiting with null/empty results when the subscription list can't be retrieved).

Suggested change
batchSize = ftk_ARGBatchSize() * (if batchMultiplier <> null then batchMultiplier else 1),
subQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId" & ftk_DemoFilter(),
Subscriptions = AzureResourceGraph.Query(subQuery, "Tenant", null, null, [resultTruncated = false]),
SubscriptionIds = Subscriptions[subscriptionId],
BatchCount = Number.RoundUp(List.Count(SubscriptionIds) / batchSize),
Batches = List.Transform({0..BatchCount-1}, each
let
batchStart = _ * batchSize,
batchIds = List.Range(SubscriptionIds, batchStart, List.Min({batchSize, List.Count(SubscriptionIds) - batchStart})),
subFilter = " | where subscriptionId in (" & Text.Combine(List.Transform(batchIds, each "'" & _ & "'"), ",") & ")",
fullQuery = query & subFilter,
Source = AzureResourceGraph.Query(fullQuery, "Tenant", null, null, [resultTruncated = false])
in
if Table.HasColumns(Source, "Results") and Table.RowCount(Source) = 1 then null else Source
),
Filtered = List.RemoveNulls(Batches),
Combined = if List.Count(Filtered) > 0 then Table.Combine(Filtered) else null
// determine effective batch size, allowing an optional multiplier
batchSize = ftk_ARGBatchSize() * (if batchMultiplier <> null then batchMultiplier else 1),
// query Azure Resource Graph for the list of subscriptions in scope
subQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId" & ftk_DemoFilter(),
Subscriptions = AzureResourceGraph.Query(subQuery, "Tenant", null, null, [resultTruncated = false]),
// validate that the subscription query returned a usable table with a subscriptionId column
ValidSubscriptions =
if Subscriptions <> null
and Table.HasColumns(Subscriptions, "subscriptionId")
and Table.RowCount(Subscriptions) > 0
then
Subscriptions
else
null,
// short-circuit with null if we cannot retrieve a valid subscription list
Combined =
if ValidSubscriptions = null then
null
else
let
SubscriptionIds = ValidSubscriptions[subscriptionId],
BatchCount = Number.RoundUp(List.Count(SubscriptionIds) / batchSize),
Batches = List.Transform(
{0 .. BatchCount - 1},
each
let
batchStart = _ * batchSize,
batchIds = List.Range(
SubscriptionIds,
batchStart,
List.Min({ batchSize, List.Count(SubscriptionIds) - batchStart })
),
subFilter = " | where subscriptionId in (" & Text.Combine(List.Transform(batchIds, each "'" & _ & "'"), ",") & ")",
fullQuery = query & subFilter,
Source = AzureResourceGraph.Query(fullQuery, "Tenant", null, null, [resultTruncated = false])
in
// handle the single-row "Results" shape by treating it as an empty result
if Table.HasColumns(Source, "Results") and Table.RowCount(Source) = 1 then null else Source
),
Filtered = List.RemoveNulls(Batches)
in
if List.Count(Filtered) > 0 then Table.Combine(Filtered) else null

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +113
batchSize = ftk_ARGBatchSize() * (if batchMultiplier <> null then batchMultiplier else 1),
subQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId" & ftk_DemoFilter(),
Subscriptions = AzureResourceGraph.Query(subQuery, "Tenant", null, null, [resultTruncated = false]),
SubscriptionIds = Subscriptions[subscriptionId],
BatchCount = Number.RoundUp(List.Count(SubscriptionIds) / batchSize),
Batches = List.Transform({0..BatchCount-1}, each
let
batchStart = _ * batchSize,
batchIds = List.Range(SubscriptionIds, batchStart, List.Min({batchSize, List.Count(SubscriptionIds) - batchStart})),
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ftk_QueryARG computes batchSize directly from ftk_ARGBatchSize and uses it in division and List.Range indexing. If a user sets ftk_ARGBatchSize() to 0 or a non-integer value, this can cause division-by-zero or type conversion failures at runtime. Consider clamping/validating to an integer >= 1 (and optionally surfacing a clearer error message).

Copilot uses AI. Check for mistakes.
batchSize = ftk_ARGBatchSize() * (if batchMultiplier <> null then batchMultiplier else 1),
subQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId" & ftk_DemoFilter(),
Subscriptions = AzureResourceGraph.Query(subQuery, "Tenant", null, null, [resultTruncated = false]),
SubscriptionIds = Subscriptions[subscriptionId],
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ftk_QueryARG assumes the subscription list query always returns a table with a [subscriptionId] column. If AzureResourceGraph.Query returns the single-row "Results" shape (for example, due to lack of permissions or transient failures), Subscriptions[subscriptionId] will throw and block all report queries. Consider applying the same null/empty-table handling used elsewhere before indexing the column (and short-circuiting with null/empty results when the subscription list can't be retrieved).

Suggested change
SubscriptionIds = Subscriptions[subscriptionId],
// defensively handle cases where the subscription list query does not return the expected [subscriptionId] column
SubscriptionIds =
if Subscriptions = null
or not Value.Is(Subscriptions, type table)
or Table.RowCount(Subscriptions) = 0
or not Table.HasColumns(Subscriptions, "subscriptionId")
then
{}
else
Subscriptions[subscriptionId],

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs: Review 👀 PR that is ready to be reviewed Tool: Power BI Power BI reports

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Governance Report is not loading says payload size limit is exceeding the limits.

6 participants