CRITICAL NOTES
- To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering
- To find the item details (including its ID) from workspace ID, item type, and item name: list all items of that type in that workspace and, then, use JMESPath filtering
Power BI Report Authoring Skill (PBIR/PBIP Format)
This skill enables reading, editing, and creation of Power BI report
definition files in the PBIR (Power BI Report) format used by PBIP
(Power BI Project) files.
Must/Prefer/Avoid
MUST
- Use this skill only for concrete PBIR/PBIP report-file mechanics such as pages, visuals, filters, slicers, navigation, bookmarks, themes, formatting, validation, Desktop reloads, and screenshots.
- Validate PBIR with
powerbi-report-author validate after each logical batch.
- Use
powerbi-desktop reload/screenshot workflows for rendered-output changes.
- Use CLI capability lookup before writing visual roles, formatting objects, enum values, selectors, or expression encodings.
PREFER
- Start from an approved
Design Brief: or _brief/report-spec.md for greenfield report builds.
- Route visual-design uncertainty to
powerbi-report-design before writing files.
- For semantic model metadata or model-side changes, use a semantic-model authoring skill, Power BI Modeling MCP, or local TMDL files when available.
AVOID
- Do not guess PBIR JSON from memory when CLI metadata or reference files are available.
- Do not use only this skill for open-ended design, report planning, or Fabric report item CRUD; pair it with
powerbi-report-design, powerbi-report-planning, or powerbi-report-management.
Quick Start Workflow
- Plan/design routing → for greenfield builds, read
powerbi-report-planning
first; for theming, visual style, layout, redesigns, or critiques, read
powerbi-report-design. Return here for PBIR mechanics. Before authoring,
use the Design Brief: yaml block from _brief/report-spec.md (or an
approved inline Design Brief: block in the conversation) as implementation
context.
- Set up/update CLIs → before first use, confirm
powerbi-report-author
and the global powerbi-desktop command are available; see
CLI Setup.
- Understand the model → use the Semantic Model MCP Server/skill if available,
or read TMDL files directly for table/column/measure names
- Desktop context → for live Desktop status, opening PBIP/PBIX files,
reloads, screenshots, or visual verification, use the
powerbi-desktop CLI from @microsoft/powerbi-desktop-bridge-cli; see
Edit → Validate → Reload → Screenshot Loop.
- Route by intent → use Topic Files and Examples to pick the relevant
guide.
- Use CLI metadata → use Authoring Metadata & Validation CLI
for exact visual roles, formatting objects, property names, enum values, and
selector requirements; do not infer these from memory.
- Check common pitfalls → read Anti-Patterns and Pitfalls
before editing or validating when the change touches visuals, bindings,
filters, formatting, layout, or Desktop rendering.
- Validate → run
powerbi-report-author validate <path-to-.Report-dir>
after every logical batch of PBIR changes; see Validation.
- Verify rendering → for any rendered-output change, use
powerbi-desktop
reload + screenshots; see Edit → Validate → Reload → Screenshot Loop
and Screenshot Review. Do not proceed until both
validation and visual review pass. For dashboard/report builds, page
scaffolding is not completion — each requested page needs data-bound visuals.
- Report back → give the user a concise summary of what was done and any
issues encountered (major and minor).
Topic Files and Examples
Use the user's intent to choose the relevant topic file(s) before editing:
| File |
When to read |
authoring.md |
Adding/modifying pages, visuals, drillthrough, interactions — includes complete JSON examples |
powerbi-desktop.md |
Live Desktop verification — powerbi-desktop commands, PID selection, reload, screenshots, errors, troubleshooting |
screenshot-review.md |
Screenshot review checklist and rendered-output troubleshooting after Desktop screenshot capture |
formatting-overview.md |
Read first for appearance changes — cascade model, encoding rules, selectors, routing to other formatting files |
formatting.md |
Editing visual.json appearance — selectors, VCOs, encoding mechanics, background-image routing, cascade |
color-strategy.md |
Chart data point colors — theme dataColors vs dataPoint.defaultColor vs dataPoint.fill with selectors, cross-visual measure-color consistency |
conditional-formatting.md |
Data-driven formatting — color gradients (FillRule), rules-based, icon sets, data bars, web URL, field value |
page-formatting.md |
Editing page.json appearance — canvas background, wallpaper, page background images |
filter-pane.md |
Filter pane (outspacePane) and filter card (filterCard) chrome — Applied/Available state styling, pane width, search/checkbox colors |
theming.md |
Creating or editing theme.json — dataColors, textClasses, visualStyles, style presets, ThemeDataColor reference |
re-theming.md |
Switching themes on a report with existing visuals — re-theming workflow (color mapping + bulk sweep), dark mode checklist, dark↔light polarity changes. Pair with theming.md when changing colors on a report with per-visual overrides. |
expressions.md |
Building field references (Column, Measure, Aggregation, Hierarchy) and sort definitions |
filters.md |
Adding/modifying filters — includes complete JSON examples |
slicers.md |
Read first when adding/modifying slicers or slicer selections — agent workflow, JSON templates, selection config |
cartesian.md |
Adding bar, column, line charts — families, roles, query patterns (multi-measure, drill hierarchy, date hierarchy), formatting |
map.md |
Adding map visuals — template, roles, geocoding workflow, handling render failures |
card.md |
Adding or formatting KPI/card visuals — cardVisual, id selectors, callout/value sizing, accent bars |
table.md |
Adding or formatting tables/matrices — tableEx, pivotTable, grow-to-fit columns, row banding |
image.md |
Adding image visuals — local resources, URLs, data-bound images, OneLake file URLs, ImageUrl validation/refusal workflow; also plot area background images for chart visuals |
shape.md |
Adding shape visuals — containers, dividers, backgrounds, reference-image matching |
textbox.md |
Adding static or dynamic textbox visuals — paragraphs, text runs, and bound value expressions |
version-control.md |
Git branching, committing, reverting — read when the task involves version control or safe rollback planning |
Greenfield / Design Handoff
This skill owns PBIR file mechanics once the work is concrete: page/visual
JSON, bindings, filters, slicers, themes, formatting, navigation, bookmarks,
validation, Desktop reloads, and screenshots.
Use powerbi-report-planning before authoring for new report/dashboard
requests, requirements gathering, dependency checks, approval, or end-to-end
build sequencing. Use powerbi-report-design for open-ended visual design,
redesign/restyle, brand/theme direction, chart selection, or layout critique.
Return here once there is an approved spec/design brief or a concrete PBIR
edit to implement — see Quick Start step 0 for how to consume the brief.
Large Build Execution
For full report/PBIP builds, do not delegate complete PBIP generation to a
subagent — the owning agent must keep the design brief, model inventory,
cross-page consistency, validation loop, and Desktop verification coordinated.
When context or repetition is the constraint, prefer a deterministic Node.js
generator that reads the approved design brief and writes PBIR JSON. If
delegation is still useful, split it by page or visual family and give each
subagent the relevant brief excerpt, exact fields/measures, and layout/visual
contract; have it return scoped PBIR JSON or a patch for the owning agent to
integrate and validate.
CLI Setup
Prerequisite: Node.js 20 or later. Check with node --version. If missing
or older, install from nodejs.org or via your package
manager — Windows: winget install OpenJS.NodeJS.LTS; macOS: brew install node;
Linux: distro package or nodesource.
Before using the CLIs in a session, ensure the latest global versions are
installed:
npm install -g @microsoft/powerbi-report-authoring-cli@latest @microsoft/powerbi-desktop-bridge-cli@latest
Confirm both are on PATH:
powerbi-report-author --version
powerbi-desktop --version
PBIR File Layout
A PBIP project on disk looks like this:
<Report>.pbip # Project manifest
├── <Report>.Report/
│ ├── .platform # Fabric metadata (type, logicalId)
│ ├── definition.pbir # Report → SemanticModel binding
│ ├── definition/
│ │ ├── version.json # Format version (e.g. "2.0.0")
│ │ ├── report.json # Report-level: themes, settings, resources
│ │ └── pages/
│ │ ├── pages.json # Page order + active page name
│ │ └── <pageId>/
│ │ ├── page.json # Page: displayName, size, type, filters
│ │ └── visuals/
│ │ └── <visualId>/
│ │ └── visual.json # Visual: type, position, query, formatting
│ ├── CustomVisuals/ # Third-party .pbiviz packages
│ └── StaticResources/
│ ├── SharedResources/BaseThemes/ # Built-in base themes
│ └── RegisteredResources/ # User images, custom theme JSON
└── <Report>.SemanticModel/ # OUT OF SCOPE
Key Files
| File |
Purpose |
Agent rule |
.platform |
Fabric/PBIP report item metadata |
Keep it with the .Report folder |
definition.pbir |
Report → semantic model binding via byPath or byConnection |
Preserve schema/version unless intentionally migrating |
version.json |
PBIR format metadata |
Preserve the full scaffolded file, including $schema |
report.json |
Report-level settings, themes, resources |
Edit through references and validate after changes |
pages.json |
Page order and active page |
Add every new page to pageOrder; preserve activePageName |
page.json |
Page metadata, size, filters |
Preserve dimensions unless resizing is approved |
visual.json |
Visual type, position, query, formatting |
Validate roles and formatting with CLI metadata |
localSettings.json |
User-local settings |
Do not commit or rely on it |
Schema URLs use the prefix developer.microsoft.com/json-schemas/fabric/item/report/definition/.
The suffixes are versioned PBIR contracts that Power BI Desktop bumps with most
releases (e.g. visualContainer/2.9.0, page/2.1.0, report/3.3.0 at the
time of writing — newer values may appear in any user's PBIP). When editing,
always preserve the existing $schema value; when adding a new file, copy
the $schema URL from an existing file of the same type in the same report.
Do not invent or bump versions on your own. Validate with powerbi-report-author validate.
Authoring Metadata & Validation CLI
Use powerbi-report-author whenever you need PBIR facts that should not be
guessed: visual types, data roles, formatting objects, property names, enum
values, selectors, expression/value encodings, and report validation. The CLI is
the source of truth for PBIR authoring details; examples and memory are not.
| Command |
Purpose |
When to use |
catalog list |
List all built-in visual types (and any deprecated entries) |
Choosing a visual type |
catalog describe <type> |
Roles, formatting keys, cardinality |
Before creating/editing a visual |
formatting list-objects <type> |
Valid objects.* keys + VCO keys; flags objects needing id selectors |
Before applying formatting |
formatting describe-object <type> <object> |
Property names, types, enum values, descriptions; _selectorHint when id selector required |
Finding exact property names and allowed values |
formatting describe-property <type> <object> <prop> |
Focused single-property lookup |
When you already know the object and want just one property |
formatting search <type> <regex> |
Regex search across all formatting objects + VCOs |
When you don't know which object a property belongs to |
formatting list-vcos |
Enumerate shared visualContainerObjects |
Auditing chrome/container formatting surface |
validate <path> |
Full validation of a .pbip or .Report directory: JSON Schema, structure, IDs, formatting properties, enum values, nesting, layout bounds, theme |
After every batch of changes |
preview-* <path> [--with-derived] |
Report inventory: preview-visuals, preview-pages, preview-filters, preview-themes |
Auditing existing report content |
--help / <command> --help |
Command syntax and available options |
Before using an unfamiliar command or flag |
More commands: powerbi-report-author-cli.md.
Validation result handling
Run powerbi-report-author validate <path-to-.Report-dir> after every logical
batch of PBIR edits.
failed / non-zero exit: fix every error before Desktop reload. Desktop may
reject or misrender invalid PBIR.
succeededWithWarnings: review warnings before proceeding. Unknown visual
types or theme visual keys usually mean a typo unless the report intentionally
uses a custom .pbiviz.
- Diagnostics include file paths and JSON paths. Use them to jump directly to
the broken node.
- For large diagnostics, use
--pretty for readable output or --out <file> to
write the full result to a file.
Visual Capability Guardrails
Use these as pre-edit safety rails. Always confirm exact roles, formatting
objects, properties, enum values, and selectors with powerbi-report-author
before editing.
Prefer modern visual types
Never create legacy visual types. If repairing an existing legacy visual,
migrate to the modern type and rebuild roles/formatting from CLI metadata.
| Do not create |
Use instead |
card |
cardVisual |
multiRowCard |
cardVisual — use multi-value cardVisual (multiple projections in Data) for multiple KPIs |
table |
tableEx |
matrix |
pivotTable |
map, filledMap |
azureMap |
Instance Selectors
Some formatting objects need { id: ... } selectors. Run formatting list-objects and formatting describe-object; follow _selectorHint and the
dual-entry pattern in references/formatting.md.
Edit → Validate → Reload → Screenshot Loop
For rendered-output changes, follow this loop. Do not report completion until
validation, reload, and screenshot review are clean.
┌──────────────────────────────────────────────────────────┐
│ 1. Edit PBIR files │
│ 2. Validate → errors? fix and go to 1 │
│ 3. Desktop status → choose the correct bridge PID │
│ 4. Desktop reload → error? fix PBIR and go to 1 │
│ 5. Screenshot/review → issues? fix and go to 1 │
│ 6. Clean → report completion │
└──────────────────────────────────────────────────────────┘
Rules:
- Step 2 —
powerbi-report-author validate <path-to-.Report-dir>. Pass the
report definition directory (e.g., Sales.Report), not the .pbip file or
project root. Fix all errors before reload — invalid PBIR errors will surface
in Desktop.
- Steps 3–5 — use
powerbi-desktop CLI: status to choose the PID, then
reload --pid <pid> for PBIP/PBIR current files and screenshots from the
same PID. Then perform the screenshot review below.
After status, if the selected instance has hasUnsavedChanges: true, do
not reload yet; ask the user to save or discard their Desktop UI changes,
rerun status, and continue only once it is false.
reload covers report/PBIR changes only. For semantic-model/TMDL changes,
use a semantic-model skill or Modeling MCP and reopen the PBIP if changes are
not reflected.
Exception: Theme JSON files are cache-keyed by name — Desktop may not
pick up edits on reload. Either rename the theme file with a random suffix
(and update report.json), or close and reopen Desktop.
Desktop CLI commands:
| Command |
Purpose |
When to use |
open "<path.pbip>" |
Launch Power BI Desktop for a PBIP/PBIX |
Starting Desktop or opening the target report |
status |
List Desktop Bridge instances, current files, report dirs, and bridge state |
Before reload/screenshot; choose the correct PID |
reload --pid <pid> |
Reload the selected Desktop instance's current PBIP report files |
After validated PBIR edits in an open PBIP |
screenshot <page-id> --pid <pid> --output <file> |
Capture one page by PBIR page ID |
Isolated page changes |
screenshot-all --pid <pid> --output-dir <dir> |
Capture every report page |
Theme, navigation, page-order, or report-wide changes |
Use powerbi-desktop screenshot <page-id> --pid <pid> when only one PBIR
page needs review. reload is supported only for PBIP-backed reports. No powerbi-desktop command accepts --report; use status
to select the Desktop instance by PID because the same PBIP can be open in more
than one process. Screenshots default to scale 2. Run reload and screenshot
operations serially per PID — never in parallel against the same PID, even as a
workaround for a slow or retryable error. Read references/powerbi-desktop.md for the
complete command reference and troubleshooting workflow.
Common Desktop CLI outcomes:
| Output/error |
Meaning |
Action |
"status": "not_connected" |
No Desktop Bridge discoverable |
Run powerbi-desktop open "<path.pbip>" or ask the user to start Desktop. If still unreachable, ask them to enable the Desktop preview feature — see docs |
AMBIGUOUS_DESKTOP_INSTANCE |
More than one Desktop Bridge instance is available |
Run powerbi-desktop status, choose the intended PID, retry with --pid |
METHOD_NOT_AVAILABLE |
Desktop build lacks a required production bridge method |
Tell the user Desktop is stale/unsupported — see docs |
HostNotReady / retryable bridge error |
Desktop is up but the report host isn't ready (often briefly after a reload) |
CLI auto-retries; rerun once if it surfaces. Do not add custom sleeps — rely on the CLI's retry path. |
Timeout (bridge error) |
A reload or screenshot exceeded the CLI's retry budget |
Confirm status shows bridgeStatus: "connected", then rerun once. If Timeout persists, raise the budget (e.g., reload --pid <pid> --wait-seconds 120). If bridgeStatus: "error" or status hangs, ask the user whether a Desktop modal dialog is blocking input. |
Cancelled during screenshot/reload |
A reload/screenshot was cancelled — usually a concurrent reload/screenshot on the same PID. Distinct from Timeout (operation ran too long). |
Run reload and screenshot serially per PID. Wait for connected via status, retry one at a time. |
ReportDefinitionValidationFailed |
Desktop rejected the PBIR definition |
Fix PBIR, run powerbi-report-author validate <path>, then reload again |
REPORT_DIR_REQUIRED |
Selected PID has no PBIP/PBIR current file; reload/screenshot-all need PBIP/PBIR state |
Select the correct PID from status or open the target PBIP |
Screenshot Review
After taking screenshots, perform an independent rendered-output review before reporting completion. Read screenshot-review.md, check layout, data rendering, formatting/theme, slicers, and common screenshot failure modes, then fix PBIR and repeat the loop until clean.
Validation
Run powerbi-report-author validate <path> after every logical batch of PBIR
changes. Prefer the .Report directory; the CLI also accepts a .pbip file or
a project root containing a single .Report directory. Errors block Desktop
reload — fix them first. Review warnings and fix unless there's a clear reason
not to.
The validator is an offline preflight covering PBIR structure, JSON/schema
validity, cross-file references, IDs/names, visual types, role bindings,
filters, formatting objects/properties/enums/selectors, visualContainerObjects,
theme registration, layout bounds, and selected Desktop/rendering failure
patterns. It does not replace Desktop reload and screenshot review.
Anti-Patterns and Pitfalls
| Pitfall |
Consequence |
Fix |
Using "Entity" inside filter Where conditions |
Filter silently fails |
Use "Source" with the alias from From |
Omitting nativeQueryRef |
Visual calculations may break |
Always include nativeQueryRef |
| Reusing visual/filter names |
Unpredictable behavior |
Generate unique IDs |
Setting visualType to invalid string |
Visual renders as error box |
Run powerbi-report-author catalog describe <type> or powerbi-report-author catalog list |
| Wrong role name for visual type |
Field is ignored; visual blank |
Match role names from powerbi-report-author catalog describe <type> |
Mixing Column and Measure types |
Query fails; visual error |
Columns use Column, measures use Measure |
Forgetting to add page to pages.json |
Page invisible |
Add to pageOrder array |
| Booleans without correct format |
Wrong type |
"true" / "false" (no suffix, unquoted in Value) |
| Numbers without type suffix |
Type mismatch |
D for decimals, L for integers |
Editing $schema version |
PBI Desktop may reject |
Preserve existing version |
Stringified JSON in paragraphs |
Textbox shows nothing |
paragraphs is a native JSON array |
| Using textbox as a thin line/divider |
Renders ~24px tall regardless of height |
Use a shape visual (rectangle) instead — shapes respect small dimensions |
visualContainerObjects as sibling of visual |
Schema validation error in PBI Desktop |
Must be inside visual object, as sibling of objects |
Using tableEx with dimension columns and measures all in Values |
Headers render but no data rows even when DAX confirms data exists |
Use pivotTable; put dimensions in Rows and measures in Values |
Using PowerShell ConvertTo-Json to edit visual JSON |
Property reordering, nesting depth truncation (-Depth default is 2) |
Use Node.js for JSON manipulation, or always pass -Depth 20 and verify structure |
| Using regex or string replacement to modify JSON files |
Corrupts nesting structure — properties end up inside sibling values, braces misalign |
Read file → JSON.parse → modify object → JSON.stringify → write back. Or use the edit tool with exact old/new string matching |
dataPoint.fill without a selector on single-series charts |
Bars/columns invisible despite data in tooltips |
Use dataPoint.defaultColor for a base color without a selector; fill requires a metadata selector |
Using dataPoint.defaultColor on multi-series charts |
All series/categories get the same color — no visual differentiation |
Use theme dataColors for consistent palette across visuals, or dataPoint.fill with metadata selectors for per-series overrides — see color-strategy.md § Color Strategy Quick Reference |
| Clustered bar/column chart colors collapse into one legend color |
The visual has a Series role but all bars and legend markers share the same hue |
Use per-series dataPoint.fill selectors or a theme dataColors palette; do not use defaultColor on clustered charts |
Relying on theme dataColors alone for cross-visual measure consistency |
Same measure gets different colors on different visuals (index-based assignment varies with projection order) |
Maintain a measure→color mapping and apply explicit dataPoint.fill/defaultColor per visual — see color-strategy.md § Cross-Visual Measure-Color Consistency |
Using ThemeDataColor for explicit per-measure dataPoint.fill with metadata selectors |
Colors silently resolve to white or black instead of expected palette color |
Use Literal hex values for explicit color assignments with metadata selectors — ThemeDataColor is unreliable in this context |
| Choosing bar/series colors without checking background contrast |
Bars or lines invisible against page/card background (e.g., white bars on white canvas) |
Always pick saturated, mid-to-dark hues that contrast with the page and VCO background colors |
show property on page-level background |
Schema error — page background only supports color, image, transparency |
Only VCO background (on visuals) has show; page background is always visible |
| Copying property names from doc examples without verifying |
Warnings or silent failures — property names vary by visual type |
Always run powerbi-report-author formatting describe-object <type> <object> for exact property names |
| Guessing which object a property belongs to |
Wasted calls checking wrong objects one by one |
Run powerbi-report-author formatting search <type> <regex> to grep across all objects at once |
| Formatting property has no effect (no error) |
Setting show: false on cardVisual outline without an id selector — validates but renders unchanged |
Check powerbi-report-author formatting describe-object <type> <object> for _selectorHint; use the dual-entry pattern (static + id selector entries) |
Using cardCalloutArea on a single-value card |
Properties validate but have no visible effect — cardCalloutArea only renders on multi-value cards (2+ measures in Data) |
Use outline/accentBar/fillCustom with { id: "default" } selector for single-value cards. For multi-value cards, cardCalloutArea controls per-callout tile styling — see card.md § Multi-Value Formatting |
Using "Fields" as the queryState role for cardVisual |
Cards render empty — PBI Desktop cannot resolve the binding. Validator reports Unknown role "Fields" and Required role "Data" missing |
cardVisual's only data role is "Data". "Fields" is the legacy card visual's role name — never carry it over. Always verify role names with powerbi-report-author catalog describe cardVisual — see card.md § Single-Value Template |
Creating separate single-value cardVisual instances for multiple related KPIs |
Wastes canvas space and misuses the visual type — cardVisual natively supports multiple projections in one tile |
Default to one multi-value cardVisual with all measures as Data projections when ≥2 related KPIs are requested. Only use separate cards when per-card styling differences are required — see card.md § When to Consolidate vs. Keep Separate |
| Adding multiple fields to button slicer Values or Label roles |
Slicer breaks or shows unexpected results — each role accepts only 1 field |
Put one field in Values, one in Label; additional fields go to Tooltips |
Looking at filterConfig on other visuals to understand slicer selections |
Slicer selections live only inside the slicer's own visual.json via expansionStates + objects.general.filter. Always read references/slicers.md first when modifying slicers |
|
| Creating an image visual without prompting for the source type |
Wrong visual structure — URL vs local file vs data field each have different schemas and expression types |
Always ask the user for the image source (local file / URL / data field / OneLake file URL) before creating the visual — see image.md § Source Types Overview |
Creating a data-bound image visual with a field that lacks dataCategory: ImageUrl |
Visual renders blank or error |
Warn the user first — the visual will render blank without dataCategory: ImageUrl. Present alternatives (other ImageUrl fields, local file, URL) and confirm before creating — see image.md § Select from data |
| Placing background image on page canvas instead of visual plot area |
User asks for "background image" alongside a visual (e.g., "column chart with background image") but image is placed on page.json → objects.background instead of visual.objects.plotArea |
When a background image is requested in the context of a specific visual, default to plotArea.image. Only use page-level background.image when the user explicitly says "page background" / "canvas background" or no visual context exists — see image.md § Plot Area Background Image |
Creating a multiRowCard visual |
Legacy multi-row card — deprecated; powerbi-report-author validate warns with PBIR_VISUAL_TYPE_DEPRECATED. Often triggered by user phrases like "multi-card", "cards for each metric", or "card per measure" |
Always use cardVisual. For multiple KPIs, use a single multi-value cardVisual with all measures as projections in the Data role — see card.md |
Using map or filledMap instead of azureMap for map visuals |
Legacy Bing Maps visuals — deprecated and must not be created; powerbi-report-author validate warns with PBIR_VISUAL_TYPE_DEPRECATED |
Always use azureMap — see map.md. If the map fails to render or geocode, debug the fields, try alternative geographic columns/coordinates, or ask the user — do not silently substitute a non-map visual without consulting the user first |
Creating tableEx/pivotTable without columnAdjustment: growToFit |
Columns shrink-wrap to content, leaving unused whitespace |
Always set columnHeaders.columnAdjustment to growToFit and autoSizeColumnWidth to true — see table.md |
| Custom table/matrix row colors with no effect (white background) |
Default style preset overrides objects-level backColorPrimary/backColorSecondary |
Set stylePreset VCO to 'None' on every tableEx/pivotTable with custom colors — see table.md § Style Presets |
| Table cells white despite dark VCO background |
visualContainerObjects.background only controls outer container — table cells paint on top |
Set dark colors in objects.values.backColorPrimary/Secondary and objects.columnHeaders.backColor, not in VCO — see re-theming.md § Dark Mode Checklist |
| Dark theme applied but cards/tables/slicers still white |
Dark mode triggers every formatting trap simultaneously |
Follow the full re-theming.md § Dark Mode Authoring Checklist — covers stylePreset, fillCustom+id selector, objects vs VCO, and contrast audit |
| Theme JSON changes do not appear after Desktop reload |
Desktop caches theme files by file name |
Rename the theme JSON with a small random suffix, update the theme registration in report.json, then reload; otherwise close and reopen Desktop |
Placing sortDefinition inside visual or at root of visual.json |
Schema validation error; sort silently ignored — chart falls back to alphabetical |
sortDefinition is a property of query — use visual.query.sortDefinition. Supported since visualConfiguration/2.2.0 |
| Container shape fill doesn't match reference |
Text invisible or wrong background color |
Match the fill color and transparency to the reference image. If the page background already provides the color, skip the shape entirely. If the shape must be invisible, verify text color still contrasts with the page canvas — see shape.md § Container Shapes |
| Shape text invisible after re-theme |
Shape text object has no explicit fontColor — text inherits theme foreground, but when fill is a light color (e.g., white pill/button) on a light page canvas, inherited dark foreground may not render or the fill blends with canvas making text vanish |
Always set explicit fontColor on shape text objects (in the { selector: { id: "default" } } entry). During re-theming, audit all shapes with text.show: true — bulk hex-replacement misses shapes that need a new fontColor property added |
Enabling logAxisScale on data with zero or negative values |
PBI Desktop silently falls back to linear scale with a warning — log of zero/negative is undefined |
Warn the user before applying. Use ask_user to present alternatives (filter negatives, switch measure, use labelDisplayUnits). Apply logAxisScale: true only after the user resolves negative values or confirms all bound values are positive — see cartesian.md § Log Scale |
| Changing theme without sweeping inline overrides |
Old colors remain on shapes, page backgrounds, nav buttons, textboxes — theme-only change has no effect on hardcoded Literal hex values at Priority 2 in the cascade |
When the report has per-visual color overrides, follow re-theming.md § Re-theming Workflow Steps 0–3: build a color mapping, update theme JSON, then bulk-sweep definition/ files for old hex values before reload |
Changing only dataColors in theme without sweeping |
Shapes, accent bars, nav button borders retain old accent colors — they use hardcoded Literal hex from the old dataColors array, not ThemeDataColor references |
Sweep ALL old dataColors[N] hex values across definition/ files. Even same-polarity "just change the accent/data colors" requests need the full sweep — shapes and nav elements commonly hardcode dataColors[0] as accent fills/outlines. |
Official Documentation
For Microsoft Learn setup guidance, support constraints, and feature
availability, use Power BI report authoring docs.
Local vendoring note (not part of the upstream skill)
Vendored verbatim from microsoft/skills-for-fabric
v0.3.13, commit b8d541c, MIT-licensed (LICENSE.upstream).
When re-syncing, diff against upstream and re-apply this section only.
Local deviations from the upstream routing:
powerbi-report-planning is not installed — use pbir-report-workflow
for end-to-end requirements/build sequencing instead.
powerbi-report-management is not installed — use fabric-rest-api /
fabric-tmdl-api (and pbir-cli publish verbs) for Fabric definition
transport.
- The Power BI Desktop Bridge loop (
powerbi-desktop open/reload/screenshot)
is skipped in this environment: the workflow here is service-first with
Fabric Git sync, and the primary models are Direct Lake, where opening a
PBIP forces remote modeling and risks overwriting the live workspace model.
For rendered visual verification use the service-side exportToFile PNG
loop instead — see pbir-report-workflow Step 12.
powerbi-report-author CLI (npm @microsoft/powerbi-report-authoring-cli,
Node >= 20) IS in scope: its offline validate and catalog / formatting
introspection commands work purely on files and complement pbir-cli.
1---2name: powerbi-report-authoring3description: Create and modify Power BI report files in PBIR/PBIP format using the `powerbi-report-author` and `powerbi-desktop` CLIs. Use when the user wants to: (1) implement an approved report spec or design brief, (2) add or edit pages, visuals, filters, slicers, bookmarks, themes, or formatting, (3) validate PBIR and verify rendering in Power BI Desktop. For open-ended visual design, use `powerbi-report-design` first. For end-to-end requirements and approval workflow, use `powerbi-report-planning` first. Triggers: "edit PBIR", "create Power BI report page", "add visual to PBIP", "format report visual", "validate Power BI report", "reload Desktop screenshot", "implement an approved PBIP report spec", "edit PBIR pages/visuals".4---56> **CRITICAL NOTES**7> 1. To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering8> 2. To find the item details (including its ID) from workspace ID, item type, and item name: list all items of that type in that workspace and, then, use JMESPath filtering910# Power BI Report Authoring Skill (PBIR/PBIP Format)1112This skill enables reading, editing, and creation of Power BI report13definition files in the **PBIR (Power BI Report)** format used by **PBIP14(Power BI Project)** files.1516## Must/Prefer/Avoid1718### MUST1920- Use this skill only for concrete PBIR/PBIP report-file mechanics such as pages, visuals, filters, slicers, navigation, bookmarks, themes, formatting, validation, Desktop reloads, and screenshots.21- Validate PBIR with `powerbi-report-author validate` after each logical batch.22- Use `powerbi-desktop` reload/screenshot workflows for rendered-output changes.23- Use CLI capability lookup before writing visual roles, formatting objects, enum values, selectors, or expression encodings.2425### PREFER2627- Start from an approved `Design Brief:` or `_brief/report-spec.md` for greenfield report builds.28- Route visual-design uncertainty to `powerbi-report-design` before writing files.29- For semantic model metadata or model-side changes, use a semantic-model authoring skill, Power BI Modeling MCP, or local TMDL files when available.3031### AVOID3233- Do not guess PBIR JSON from memory when CLI metadata or reference files are available.34- Do not use only this skill for open-ended design, report planning, or Fabric report item CRUD; pair it with `powerbi-report-design`, `powerbi-report-planning`, or `powerbi-report-management`.3536## Quick Start Workflow37380. **Plan/design routing** → for greenfield builds, read `powerbi-report-planning`39 first; for theming, visual style, layout, redesigns, or critiques, read40 `powerbi-report-design`. Return here for PBIR mechanics. Before authoring,41 use the `Design Brief:` yaml block from `_brief/report-spec.md` (or an42 approved inline `Design Brief:` block in the conversation) as implementation43 context.441. **Set up/update CLIs** → before first use, confirm `powerbi-report-author`45 and the global `powerbi-desktop` command are available; see46 [CLI Setup](#cli-setup).472. **Understand the model** → use the Semantic Model MCP Server/skill if available,48 or read TMDL files directly for table/column/measure names493. **Desktop context** → for live Desktop status, opening PBIP/PBIX files,50 reloads, screenshots, or visual verification, use the51 `powerbi-desktop` CLI from `@microsoft/powerbi-desktop-bridge-cli`; see52 [Edit → Validate → Reload → Screenshot Loop](#edit--validate--reload--screenshot-loop).534. **Route by intent** → use [Topic Files and Examples](#topic-files-and-examples) to pick the relevant54 guide.555. **Use CLI metadata** → use [Authoring Metadata & Validation CLI](#authoring-metadata--validation-cli)56 for exact visual roles, formatting objects, property names, enum values, and57 selector requirements; do not infer these from memory.586. **Check common pitfalls** → read [Anti-Patterns and Pitfalls](#anti-patterns-and-pitfalls)59 before editing or validating when the change touches visuals, bindings,60 filters, formatting, layout, or Desktop rendering.617. **Validate** → run `powerbi-report-author validate <path-to-.Report-dir>`62 after every logical batch of PBIR changes; see [Validation](#validation).638. **Verify rendering** → for any rendered-output change, use `powerbi-desktop`64 reload + screenshots; see [Edit → Validate → Reload → Screenshot Loop](#edit--validate--reload--screenshot-loop)65 and [Screenshot Review](#screenshot-review). Do not proceed until both66 validation and visual review pass. For dashboard/report builds, page67 scaffolding is not completion — each requested page needs data-bound visuals.689. **Report back** → give the user a concise summary of what was done and any69 issues encountered (major and minor).7071## Topic Files and Examples7273Use the user's intent to choose the relevant topic file(s) before editing:7475| File | When to read |76|------|-------------|77| [`authoring.md`](references/authoring.md) | Adding/modifying pages, visuals, drillthrough, interactions — includes complete JSON examples |78| [`powerbi-desktop.md`](references/powerbi-desktop.md) | Live Desktop verification — `powerbi-desktop` commands, PID selection, reload, screenshots, errors, troubleshooting |79| [`screenshot-review.md`](references/screenshot-review.md) | Screenshot review checklist and rendered-output troubleshooting after Desktop screenshot capture |80| [`formatting-overview.md`](references/formatting-overview.md) | **Read first for appearance changes** — cascade model, encoding rules, selectors, routing to other formatting files |81| [`formatting.md`](references/formatting.md) | Editing `visual.json` appearance — selectors, VCOs, encoding mechanics, background-image routing, cascade |82| [`color-strategy.md`](references/color-strategy.md) | Chart data point colors — theme `dataColors` vs `dataPoint.defaultColor` vs `dataPoint.fill` with selectors, cross-visual measure-color consistency |83| [`conditional-formatting.md`](references/conditional-formatting.md) | Data-driven formatting — color gradients (FillRule), rules-based, icon sets, data bars, web URL, field value |84| [`page-formatting.md`](references/page-formatting.md) | Editing `page.json` appearance — canvas background, wallpaper, page background images |85| [`filter-pane.md`](references/filter-pane.md) | Filter pane (`outspacePane`) and filter card (`filterCard`) chrome — Applied/Available state styling, pane width, search/checkbox colors |86| [`theming.md`](references/theming.md) | Creating or editing `theme.json` — dataColors, textClasses, visualStyles, style presets, ThemeDataColor reference |87| [`re-theming.md`](references/re-theming.md) | **Switching themes on a report with existing visuals** — re-theming workflow (color mapping + bulk sweep), dark mode checklist, dark↔light polarity changes. Pair with `theming.md` when changing colors on a report with per-visual overrides. |88| [`expressions.md`](references/expressions.md) | Building field references (Column, Measure, Aggregation, Hierarchy) and sort definitions |89| [`filters.md`](references/filters.md) | Adding/modifying filters — includes complete JSON examples |90| [`slicers.md`](references/slicers.md) | **Read first** when adding/modifying slicers or slicer selections — agent workflow, JSON templates, selection config |91| [`cartesian.md`](references/cartesian.md) | Adding bar, column, line charts — families, roles, query patterns (multi-measure, drill hierarchy, date hierarchy), formatting |92| [`map.md`](references/map.md) | Adding map visuals — template, roles, geocoding workflow, handling render failures |93| [`card.md`](references/card.md) | Adding or formatting KPI/card visuals — `cardVisual`, id selectors, callout/value sizing, accent bars |94| [`table.md`](references/table.md) | Adding or formatting tables/matrices — `tableEx`, `pivotTable`, grow-to-fit columns, row banding |95| [`image.md`](references/image.md) | Adding image visuals — local resources, URLs, data-bound images, OneLake file URLs, ImageUrl validation/refusal workflow; also plot area background images for chart visuals |96| [`shape.md`](references/shape.md) | Adding shape visuals — containers, dividers, backgrounds, reference-image matching |97| [`textbox.md`](references/textbox.md) | Adding static or dynamic textbox visuals — paragraphs, text runs, and bound value expressions |98| [`version-control.md`](references/version-control.md) | Git branching, committing, reverting — read when the task involves version control or safe rollback planning |99100### Greenfield / Design Handoff101102> This skill owns PBIR file mechanics once the work is concrete: page/visual103> JSON, bindings, filters, slicers, themes, formatting, navigation, bookmarks,104> validation, Desktop reloads, and screenshots.105>106> Use `powerbi-report-planning` before authoring for new report/dashboard107> requests, requirements gathering, dependency checks, approval, or end-to-end108> build sequencing. Use `powerbi-report-design` for open-ended visual design,109> redesign/restyle, brand/theme direction, chart selection, or layout critique.110> Return here once there is an approved spec/design brief or a concrete PBIR111> edit to implement — see Quick Start step 0 for how to consume the brief.112113### Large Build Execution114115For full report/PBIP builds, do **not** delegate complete PBIP generation to a116subagent — the owning agent must keep the design brief, model inventory,117cross-page consistency, validation loop, and Desktop verification coordinated.118119When context or repetition is the constraint, prefer a deterministic Node.js120generator that reads the approved design brief and writes PBIR JSON. If121delegation is still useful, split it by page or visual family and give each122subagent the relevant brief excerpt, exact fields/measures, and layout/visual123contract; have it return scoped PBIR JSON or a patch for the owning agent to124integrate and validate.125126## CLI Setup127128**Prerequisite: Node.js 20 or later.** Check with `node --version`. If missing129or older, install from [nodejs.org](https://nodejs.org/) or via your package130manager — Windows: `winget install OpenJS.NodeJS.LTS`; macOS: `brew install node`;131Linux: distro package or [nodesource](https://github.com/nodesource/distributions).132133Before using the CLIs in a session, ensure the latest global versions are134installed:135136```bash137npm install -g @microsoft/powerbi-report-authoring-cli@latest @microsoft/powerbi-desktop-bridge-cli@latest138```139140Confirm both are on `PATH`:141142```bash143powerbi-report-author --version144powerbi-desktop --version145```146147## PBIR File Layout148149A PBIP project on disk looks like this:150151```text152<Report>.pbip # Project manifest153├── <Report>.Report/154│ ├── .platform # Fabric metadata (type, logicalId)155│ ├── definition.pbir # Report → SemanticModel binding156│ ├── definition/157│ │ ├── version.json # Format version (e.g. "2.0.0")158│ │ ├── report.json # Report-level: themes, settings, resources159│ │ └── pages/160│ │ ├── pages.json # Page order + active page name161│ │ └── <pageId>/162│ │ ├── page.json # Page: displayName, size, type, filters163│ │ └── visuals/164│ │ └── <visualId>/165│ │ └── visual.json # Visual: type, position, query, formatting166│ ├── CustomVisuals/ # Third-party .pbiviz packages167│ └── StaticResources/168│ ├── SharedResources/BaseThemes/ # Built-in base themes169│ └── RegisteredResources/ # User images, custom theme JSON170└── <Report>.SemanticModel/ # OUT OF SCOPE171```172173### Key Files174175| File | Purpose | Agent rule |176|------|---------|------------|177| `.platform` | Fabric/PBIP report item metadata | Keep it with the `.Report` folder |178| `definition.pbir` | Report → semantic model binding via `byPath` or `byConnection` | Preserve schema/version unless intentionally migrating |179| `version.json` | PBIR format metadata | Preserve the full scaffolded file, including `$schema` |180| `report.json` | Report-level settings, themes, resources | Edit through references and validate after changes |181| `pages.json` | Page order and active page | Add every new page to `pageOrder`; preserve `activePageName` |182| `page.json` | Page metadata, size, filters | Preserve dimensions unless resizing is approved |183| `visual.json` | Visual type, position, query, formatting | Validate roles and formatting with CLI metadata |184| `localSettings.json` | User-local settings | Do not commit or rely on it |185186Schema URLs use the prefix `developer.microsoft.com/json-schemas/fabric/item/report/definition/`.187The suffixes are versioned PBIR contracts that Power BI Desktop bumps with most188releases (e.g. `visualContainer/2.9.0`, `page/2.1.0`, `report/3.3.0` at the189time of writing — newer values may appear in any user's PBIP). When editing,190**always preserve the existing `$schema` value**; when adding a new file, copy191the `$schema` URL from an existing file of the same type in the same report.192Do not invent or bump versions on your own. Validate with `powerbi-report-author validate`.193194---195196## Authoring Metadata & Validation CLI197198Use `powerbi-report-author` whenever you need PBIR facts that should not be199guessed: visual types, data roles, formatting objects, property names, enum200values, selectors, expression/value encodings, and report validation. The CLI is201the source of truth for PBIR authoring details; examples and memory are not.202203| Command | Purpose | When to use |204|---------|---------|-------------|205| `catalog list` | List all built-in visual types (and any deprecated entries) | Choosing a visual type |206| `catalog describe <type>` | Roles, formatting keys, cardinality | Before creating/editing a visual |207| `formatting list-objects <type>` | Valid `objects.*` keys + VCO keys; flags objects needing id selectors | Before applying formatting |208| `formatting describe-object <type> <object>` | Property names, types, enum values, descriptions; `_selectorHint` when id selector required | Finding exact property names and allowed values |209| `formatting describe-property <type> <object> <prop>` | Focused single-property lookup | When you already know the object and want just one property |210| `formatting search <type> <regex>` | Regex search across all formatting objects + VCOs | **When you don't know which object a property belongs to** |211| `formatting list-vcos` | Enumerate shared visualContainerObjects | Auditing chrome/container formatting surface |212| `validate <path>` | Full validation of a `.pbip` or `.Report` directory: JSON Schema, structure, IDs, formatting properties, enum values, nesting, layout bounds, theme | **After every batch of changes** |213| `preview-* <path> [--with-derived]` | Report inventory: `preview-visuals`, `preview-pages`, `preview-filters`, `preview-themes` | Auditing existing report content |214| `--help` / `<command> --help` | Command syntax and available options | Before using an unfamiliar command or flag |215216More commands: [`powerbi-report-author-cli.md`](references/powerbi-report-author-cli.md).217218### Validation result handling219220Run `powerbi-report-author validate <path-to-.Report-dir>` after every logical221batch of PBIR edits.222223- `failed` / non-zero exit: fix every error before Desktop reload. Desktop may224 reject or misrender invalid PBIR.225- `succeededWithWarnings`: review warnings before proceeding. Unknown visual226 types or theme visual keys usually mean a typo unless the report intentionally227 uses a custom `.pbiviz`.228- Diagnostics include file paths and JSON paths. Use them to jump directly to229 the broken node.230- For large diagnostics, use `--pretty` for readable output or `--out <file>` to231 write the full result to a file.232233## Visual Capability Guardrails234235Use these as pre-edit safety rails. Always confirm exact roles, formatting236objects, properties, enum values, and selectors with `powerbi-report-author`237before editing.238239### Prefer modern visual types240241Never create legacy visual types. If repairing an existing legacy visual,242migrate to the modern type and rebuild roles/formatting from CLI metadata.243244| Do not create | Use instead |245|---|---|246| `card` | `cardVisual` |247| `multiRowCard` | `cardVisual` — use multi-value `cardVisual` (multiple projections in `Data`) for multiple KPIs |248| `table` | `tableEx` |249| `matrix` | `pivotTable` |250| `map`, `filledMap` | `azureMap` |251252### Instance Selectors253254Some formatting objects need `{ id: ... }` selectors. Run `formatting255list-objects` and `formatting describe-object`; follow `_selectorHint` and the256dual-entry pattern in `references/formatting.md`.257258## Edit → Validate → Reload → Screenshot Loop259260For rendered-output changes, follow this loop. Do not report completion until261validation, reload, and screenshot review are clean.262263```text264┌──────────────────────────────────────────────────────────┐265│ 1. Edit PBIR files │266│ 2. Validate → errors? fix and go to 1 │267│ 3. Desktop status → choose the correct bridge PID │268│ 4. Desktop reload → error? fix PBIR and go to 1 │269│ 5. Screenshot/review → issues? fix and go to 1 │270│ 6. Clean → report completion │271└──────────────────────────────────────────────────────────┘272```273274**Rules:**275- **Step 2** — `powerbi-report-author validate <path-to-.Report-dir>`. Pass the276 report definition directory (e.g., `Sales.Report`), not the `.pbip` file or277 project root. Fix all errors before reload — invalid PBIR errors will surface278 in Desktop.279- **Steps 3–5** — use `powerbi-desktop` CLI: `status` to choose the PID, then280 `reload --pid <pid>` for PBIP/PBIR current files and screenshots from the281 same PID. Then perform the screenshot review below.282 After `status`, if the selected instance has `hasUnsavedChanges: true`, do283 not reload yet; ask the user to save or discard their Desktop UI changes,284 rerun `status`, and continue only once it is false.285 `reload` covers report/PBIR changes only. For semantic-model/TMDL changes,286 use a semantic-model skill or Modeling MCP and reopen the PBIP if changes are287 not reflected.288 **Exception:** Theme JSON files are cache-keyed by name — Desktop may not289 pick up edits on reload. Either rename the theme file with a random suffix290 (and update `report.json`), or close and reopen Desktop.291292**Desktop CLI commands:**293294| Command | Purpose | When to use |295|---|---|---|296| `open "<path.pbip>"` | Launch Power BI Desktop for a PBIP/PBIX | Starting Desktop or opening the target report |297| `status` | List Desktop Bridge instances, current files, report dirs, and bridge state | Before reload/screenshot; choose the correct PID |298| `reload --pid <pid>` | Reload the selected Desktop instance's current PBIP report files | After validated PBIR edits in an open PBIP |299| `screenshot <page-id> --pid <pid> --output <file>` | Capture one page by PBIR page ID | Isolated page changes |300| `screenshot-all --pid <pid> --output-dir <dir>` | Capture every report page | Theme, navigation, page-order, or report-wide changes |301302Use `powerbi-desktop screenshot <page-id> --pid <pid>` when only one PBIR303page needs review. `reload` is supported only for PBIP-backed reports. No `powerbi-desktop` command accepts `--report`; use `status`304to select the Desktop instance by PID because the same PBIP can be open in more305than one process. Screenshots default to scale `2`. Run reload and screenshot306operations serially per PID — never in parallel against the same PID, even as a307workaround for a slow or retryable error. Read `references/powerbi-desktop.md` for the308complete command reference and troubleshooting workflow.309310**Common Desktop CLI outcomes:**311312| Output/error | Meaning | Action |313|--------------|---------|--------|314| `"status": "not_connected"` | No Desktop Bridge discoverable | Run `powerbi-desktop open "<path.pbip>"` or ask the user to start Desktop. If still unreachable, ask them to enable the Desktop preview feature — see [docs](https://aka.ms/Report_Authoring_skill_LearnDocs) |315| `AMBIGUOUS_DESKTOP_INSTANCE` | More than one Desktop Bridge instance is available | Run `powerbi-desktop status`, choose the intended PID, retry with `--pid` |316| `METHOD_NOT_AVAILABLE` | Desktop build lacks a required production bridge method | Tell the user Desktop is stale/unsupported — see [docs](https://aka.ms/Report_Authoring_skill_LearnDocs) |317| `HostNotReady` / retryable bridge error | Desktop is up but the report host isn't ready (often briefly after a reload) | CLI auto-retries; rerun once if it surfaces. Do not add custom sleeps — rely on the CLI's retry path. |318| `Timeout` (bridge error) | A reload or screenshot exceeded the CLI's retry budget | Confirm `status` shows `bridgeStatus: "connected"`, then rerun once. If `Timeout` persists, raise the budget (e.g., `reload --pid <pid> --wait-seconds 120`). If `bridgeStatus: "error"` or `status` hangs, ask the user whether a Desktop modal dialog is blocking input. |319| `Cancelled` during screenshot/reload | A reload/screenshot was cancelled — usually a concurrent reload/screenshot on the same PID. Distinct from `Timeout` (operation ran too long). | Run reload and screenshot serially per PID. Wait for `connected` via `status`, retry one at a time. |320| `ReportDefinitionValidationFailed` | Desktop rejected the PBIR definition | Fix PBIR, run `powerbi-report-author validate <path>`, then reload again |321| `REPORT_DIR_REQUIRED` | Selected PID has no PBIP/PBIR current file; reload/screenshot-all need PBIP/PBIR state | Select the correct PID from `status` or open the target PBIP |322323### Screenshot Review324325After taking screenshots, perform an independent rendered-output review before reporting completion. Read [`screenshot-review.md`](references/screenshot-review.md), check layout, data rendering, formatting/theme, slicers, and common screenshot failure modes, then fix PBIR and repeat the loop until clean.326327---328329## Validation330331Run `powerbi-report-author validate <path>` after every logical batch of PBIR332changes. Prefer the `.Report` directory; the CLI also accepts a `.pbip` file or333a project root containing a single `.Report` directory. Errors block Desktop334reload — fix them first. Review warnings and fix unless there's a clear reason335not to.336337The validator is an offline preflight covering PBIR structure, JSON/schema338validity, cross-file references, IDs/names, visual types, role bindings,339filters, formatting objects/properties/enums/selectors, visualContainerObjects,340theme registration, layout bounds, and selected Desktop/rendering failure341patterns. It does not replace Desktop reload and screenshot review.342343---344345## Anti-Patterns and Pitfalls346347| Pitfall | Consequence | Fix |348|---------|-------------|-----|349| Using `"Entity"` inside filter `Where` conditions | Filter silently fails | Use `"Source"` with the alias from `From` |350| Omitting `nativeQueryRef` | Visual calculations may break | Always include `nativeQueryRef` |351| Reusing visual/filter names | Unpredictable behavior | Generate unique IDs |352| Setting `visualType` to invalid string | Visual renders as error box | Run `powerbi-report-author catalog describe <type>` or `powerbi-report-author catalog list` |353| Wrong role name for visual type | Field is ignored; visual blank | Match role names from `powerbi-report-author catalog describe <type>` |354| Mixing `Column` and `Measure` types | Query fails; visual error | Columns use `Column`, measures use `Measure` |355| Forgetting to add page to `pages.json` | Page invisible | Add to `pageOrder` array |356| Booleans without correct format | Wrong type | `"true"` / `"false"` (no suffix, unquoted in Value) |357| Numbers without type suffix | Type mismatch | `D` for decimals, `L` for integers |358| Editing `$schema` version | PBI Desktop may reject | Preserve existing version |359| Stringified JSON in `paragraphs` | Textbox shows nothing | `paragraphs` is a native JSON array |360| Using textbox as a thin line/divider | Renders ~24px tall regardless of `height` | Use a `shape` visual (rectangle) instead — shapes respect small dimensions |361| `visualContainerObjects` as sibling of `visual` | Schema validation error in PBI Desktop | Must be **inside** `visual` object, as sibling of `objects` |362| Using `tableEx` with dimension columns and measures all in `Values` | Headers render but no data rows even when DAX confirms data exists | Use `pivotTable`; put dimensions in `Rows` and measures in `Values` |363| Using PowerShell `ConvertTo-Json` to edit visual JSON | Property reordering, nesting depth truncation (`-Depth` default is 2) | Use Node.js for JSON manipulation, or always pass `-Depth 20` and verify structure |364| Using regex or string replacement to modify JSON files | Corrupts nesting structure — properties end up inside sibling values, braces misalign | Read file → `JSON.parse` → modify object → `JSON.stringify` → write back. Or use the `edit` tool with exact old/new string matching |365| `dataPoint.fill` without a selector on single-series charts | Bars/columns invisible despite data in tooltips | Use `dataPoint.defaultColor` for a base color without a selector; `fill` requires a `metadata` selector |366| Using `dataPoint.defaultColor` on multi-series charts | All series/categories get the same color — no visual differentiation | Use theme `dataColors` for consistent palette across visuals, or `dataPoint.fill` with `metadata` selectors for per-series overrides — see [color-strategy.md § Color Strategy Quick Reference](references/color-strategy.md#color-strategy-quick-reference) |367| Clustered bar/column chart colors collapse into one legend color | The visual has a Series role but all bars and legend markers share the same hue | Use per-series `dataPoint.fill` selectors or a theme `dataColors` palette; do not use `defaultColor` on clustered charts |368| Relying on theme `dataColors` alone for cross-visual measure consistency | Same measure gets different colors on different visuals (index-based assignment varies with projection order) | Maintain a measure→color mapping and apply explicit `dataPoint.fill`/`defaultColor` per visual — see [color-strategy.md § Cross-Visual Measure-Color Consistency](references/color-strategy.md#pattern-cross-visual-measure-color-consistency) |369| Using `ThemeDataColor` for explicit per-measure `dataPoint.fill` with metadata selectors | Colors silently resolve to white or black instead of expected palette color | Use `Literal` hex values for explicit color assignments with metadata selectors — `ThemeDataColor` is unreliable in this context |370| Choosing bar/series colors without checking background contrast | Bars or lines invisible against page/card background (e.g., white bars on white canvas) | Always pick saturated, mid-to-dark hues that contrast with the page and VCO background colors |371| `show` property on page-level `background` | Schema error — page `background` only supports `color`, `image`, `transparency` | Only VCO `background` (on visuals) has `show`; page background is always visible |372| Copying property names from doc examples without verifying | Warnings or silent failures — property names vary by visual type | Always run `powerbi-report-author formatting describe-object <type> <object>` for exact property names |373| Guessing which object a property belongs to | Wasted calls checking wrong objects one by one | Run `powerbi-report-author formatting search <type> <regex>` to grep across all objects at once |374| Formatting property has no effect (no error) | Setting `show: false` on cardVisual outline without an id selector — validates but renders unchanged | Check `powerbi-report-author formatting describe-object <type> <object>` for `_selectorHint`; use the dual-entry pattern (static + id selector entries) |375| Using `cardCalloutArea` on a single-value card | Properties validate but have no visible effect — `cardCalloutArea` only renders on multi-value cards (2+ measures in Data) | Use `outline`/`accentBar`/`fillCustom` with `{ id: "default" }` selector for single-value cards. For multi-value cards, `cardCalloutArea` controls per-callout tile styling — see [card.md § Multi-Value Formatting](references/card.md#multi-value-formatting) |376| Using `"Fields"` as the `queryState` role for `cardVisual` | Cards render empty — PBI Desktop cannot resolve the binding. Validator reports `Unknown role "Fields"` and `Required role "Data" missing` | `cardVisual`'s only data role is `"Data"`. `"Fields"` is the legacy `card` visual's role name — never carry it over. Always verify role names with `powerbi-report-author catalog describe cardVisual` — see [card.md § Single-Value Template](references/card.md#single-value-template) |377| Creating separate single-value `cardVisual` instances for multiple related KPIs | Wastes canvas space and misuses the visual type — `cardVisual` natively supports multiple projections in one tile | Default to one multi-value `cardVisual` with all measures as `Data` projections when ≥2 related KPIs are requested. Only use separate cards when per-card styling differences are required — see [card.md § When to Consolidate vs. Keep Separate](references/card.md#when-to-consolidate-vs-keep-separate) |378| Adding multiple fields to button slicer Values or Label roles | Slicer breaks or shows unexpected results — each role accepts only 1 field | Put one field in Values, one in Label; additional fields go to Tooltips |379| Looking at `filterConfig` on other visuals to understand slicer selections | Slicer selections live **only** inside the slicer's own `visual.json` via `expansionStates` + `objects.general.filter`. Always read `references/slicers.md` first when modifying slicers |380| Creating an image visual without prompting for the source type | Wrong visual structure — URL vs local file vs data field each have different schemas and expression types | Always ask the user for the image source (local file / URL / data field / OneLake file URL) before creating the visual — see [image.md § Source Types Overview](references/image.md#source-types-overview) |381| Creating a data-bound image visual with a field that lacks `dataCategory: ImageUrl` | Visual renders blank or error | **Warn the user first** — the visual will render blank without `dataCategory: ImageUrl`. Present alternatives (other ImageUrl fields, local file, URL) and confirm before creating — see [image.md § Select from data](references/image.md#3-select-from-data) |382| Placing background image on page canvas instead of visual plot area | User asks for "background image" alongside a visual (e.g., "column chart with background image") but image is placed on `page.json → objects.background` instead of `visual.objects.plotArea` | When a background image is requested in the context of a specific visual, default to `plotArea.image`. Only use page-level `background.image` when the user explicitly says "page background" / "canvas background" or no visual context exists — see [image.md § Plot Area Background Image](references/image.md#plot-area-background-image-plotareaimage) |383| Creating a `multiRowCard` visual | Legacy multi-row card — deprecated; `powerbi-report-author validate` warns with `PBIR_VISUAL_TYPE_DEPRECATED`. Often triggered by user phrases like "multi-card", "cards for each metric", or "card per measure" | Always use `cardVisual`. For multiple KPIs, use a single multi-value `cardVisual` with all measures as projections in the `Data` role — see [card.md](references/card.md#multi-value-template) |384| Using `map` or `filledMap` instead of `azureMap` for map visuals | Legacy Bing Maps visuals — deprecated and must not be created; `powerbi-report-author validate` warns with `PBIR_VISUAL_TYPE_DEPRECATED` | Always use `azureMap` — see [map.md](references/map.md). If the map fails to render or geocode, debug the fields, try alternative geographic columns/coordinates, or ask the user — do **not** silently substitute a non-map visual without consulting the user first |385| Creating `tableEx`/`pivotTable` without `columnAdjustment: growToFit` | Columns shrink-wrap to content, leaving unused whitespace | Always set `columnHeaders.columnAdjustment` to `growToFit` and `autoSizeColumnWidth` to `true` — see [table.md](references/table.md#default-rule--grow-to-fit) |386| Custom table/matrix row colors with no effect (white background) | Default style preset overrides `objects`-level `backColorPrimary`/`backColorSecondary` | Set `stylePreset` VCO to `'None'` on every `tableEx`/`pivotTable` with custom colors — see [table.md § Style Presets](references/table.md#style-presets-for-tables) |387| Table cells white despite dark VCO background | `visualContainerObjects.background` only controls outer container — table cells paint on top | Set dark colors in `objects.values.backColorPrimary/Secondary` and `objects.columnHeaders.backColor`, not in VCO — see [re-theming.md § Dark Mode Checklist](references/re-theming.md#dark-mode-authoring-checklist) |388| Dark theme applied but cards/tables/slicers still white | Dark mode triggers every formatting trap simultaneously | Follow the full [re-theming.md § Dark Mode Authoring Checklist](references/re-theming.md#dark-mode-authoring-checklist) — covers stylePreset, fillCustom+id selector, objects vs VCO, and contrast audit |389| Theme JSON changes do not appear after Desktop reload | Desktop caches theme files by file name | Rename the theme JSON with a small random suffix, update the theme registration in `report.json`, then reload; otherwise close and reopen Desktop |390| Placing `sortDefinition` inside `visual` or at root of `visual.json` | Schema validation error; sort silently ignored — chart falls back to alphabetical | `sortDefinition` is a property of **`query`** — use `visual.query.sortDefinition`. Supported since `visualConfiguration/2.2.0` |391| Container shape fill doesn't match reference | Text invisible or wrong background color | Match the fill color and transparency to the reference image. If the page background already provides the color, skip the shape entirely. If the shape must be invisible, verify text color still contrasts with the page canvas — see [shape.md § Container Shapes](references/shape.md#container-shapes) |392| Shape text invisible after re-theme | Shape `text` object has no explicit `fontColor` — text inherits theme foreground, but when `fill` is a light color (e.g., white pill/button) on a light page canvas, inherited dark foreground may not render or the fill blends with canvas making text vanish | Always set explicit `fontColor` on shape `text` objects (in the `{ selector: { id: "default" } }` entry). During re-theming, audit all shapes with `text.show: true` — bulk hex-replacement misses shapes that need a *new* `fontColor` property added |393| Enabling `logAxisScale` on data with zero or negative values | PBI Desktop silently falls back to linear scale with a warning — log of zero/negative is undefined | **Warn the user before applying.** Use `ask_user` to present alternatives (filter negatives, switch measure, use `labelDisplayUnits`). Apply `logAxisScale: true` only after the user resolves negative values or confirms all bound values are positive — see [cartesian.md § Log Scale](references/cartesian.md#log-scale-logaxisscale) |394| Changing theme without sweeping inline overrides | Old colors remain on shapes, page backgrounds, nav buttons, textboxes — theme-only change has no effect on hardcoded `Literal` hex values at Priority 2 in the cascade | When the report has per-visual color overrides, follow [re-theming.md § Re-theming Workflow](references/re-theming.md#re-theming-an-existing-report) Steps 0–3: build a color mapping, update theme JSON, then bulk-sweep `definition/` files for old hex values before reload |395| Changing only `dataColors` in theme without sweeping | Shapes, accent bars, nav button borders retain old accent colors — they use hardcoded Literal hex from the old `dataColors` array, not `ThemeDataColor` references | Sweep ALL old `dataColors[N]` hex values across `definition/` files. Even same-polarity "just change the accent/data colors" requests need the full sweep — shapes and nav elements commonly hardcode `dataColors[0]` as accent fills/outlines. |396397## Official Documentation398399For Microsoft Learn setup guidance, support constraints, and feature400availability, use [Power BI report authoring docs](https://aka.ms/Report_Authoring_skill_LearnDocs).401402## Local vendoring note (not part of the upstream skill)403404Vendored verbatim from [microsoft/skills-for-fabric](https://github.com/microsoft/skills-for-fabric)405v0.3.13, commit `b8d541c`, MIT-licensed ([LICENSE.upstream](LICENSE.upstream)).406When re-syncing, diff against upstream and re-apply this section only.407408Local deviations from the upstream routing:409410- `powerbi-report-planning` is **not installed** — use `pbir-report-workflow`411 for end-to-end requirements/build sequencing instead.412- `powerbi-report-management` is **not installed** — use `fabric-rest-api` /413 `fabric-tmdl-api` (and `pbir-cli` publish verbs) for Fabric definition414 transport.415- The Power BI Desktop Bridge loop (`powerbi-desktop` open/reload/screenshot)416 is **skipped in this environment**: the workflow here is service-first with417 Fabric Git sync, and the primary models are Direct Lake, where opening a418 PBIP forces remote modeling and risks overwriting the live workspace model.419 For rendered visual verification use the service-side `exportToFile` PNG420 loop instead — see `pbir-report-workflow` Step 12.421- `powerbi-report-author` CLI (npm `@microsoft/powerbi-report-authoring-cli`,422 Node >= 20) IS in scope: its offline `validate` and `catalog` / `formatting`423 introspection commands work purely on files and complement `pbir-cli`.