|
| 1 | +--- |
| 2 | +uid: composite-model-measure-formatting |
| 3 | +title: Measure Format Properties in Composite Models |
| 4 | +author: Support Team |
| 5 | +updated: 2026-01-26 |
| 6 | +applies_to: |
| 7 | + products: |
| 8 | + - product: Tabular Editor 2 |
| 9 | + full: true |
| 10 | + - product: Tabular Editor 3 |
| 11 | + editions: |
| 12 | + - edition: Desktop |
| 13 | + full: true |
| 14 | + - edition: Business |
| 15 | + full: true |
| 16 | + - edition: Enterprise |
| 17 | + full: true |
| 18 | +--- |
| 19 | + |
| 20 | +# Measure Format Properties in Composite Models |
| 21 | + |
| 22 | +When working with composite models that use a Live connection to Analysis Services (SSAS/AAS), you may encounter validation errors or confusing behavior when editing measure formatting properties. A common error message is: |
| 23 | + |
| 24 | +**"A measure is not allowed to have both FormatString and Format Expression."** |
| 25 | + |
| 26 | +This article explains why this occurs and how to resolve it. |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Understanding the Issue |
| 31 | + |
| 32 | +Composite models combine local Power BI tables with remote tables from an SSAS/AAS semantic model via a Live connection. In this architecture, measure formatting can be ambiguous: |
| 33 | + |
| 34 | +- **FormatString**: A static format definition (e.g., "0.00" for currency). |
| 35 | +- **Format String Expression**: A dynamic format string evaluated at query time. |
| 36 | + |
| 37 | +The error occurs because the model ends up with both a static format and a dynamic format expression simultaneously—a state that is not allowed by the Tabular Object Model (TOM). |
| 38 | + |
| 39 | +### Why this happens |
| 40 | + |
| 41 | +In composite models: |
| 42 | + |
| 43 | +1. **Ownership ambiguity**: Remote measures are owned by the remote SSAS/AAS model. When you edit formatting in Tabular Editor, you may be trying to override remote metadata, which creates conflicts. |
| 44 | + |
| 45 | +2. **Metadata synchronization**: When a Format String Expression is present on a measure, the FormatString often appears as "Custom" to indicate dynamic formatting is active. If you then try to set a static FormatString simultaneously, both properties become populated, triggering the validation error. |
| 46 | + |
| 47 | +3. **Persistence constraints**: Changes to remote measure metadata may not persist cleanly because the remote model retains authoritative control. This leaves the local composite model in an inconsistent state. |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## Root Causes |
| 52 | + |
| 53 | +### Remote measure formatting |
| 54 | + |
| 55 | +If the problematic measure is defined in the remote SSAS/AAS model: |
| 56 | + |
| 57 | +- Formatting should be managed in the source model, not in the Power BI composite model. |
| 58 | +- Attempting to override remote measure formatting in Power BI can result in both FormatString and Format String Expression being populated, leading to the validation error. |
| 59 | + |
| 60 | +### Script or automation setting both properties |
| 61 | + |
| 62 | +- If you are using C# scripts, Power Query transformations, or BPA rules to apply formatting, ensure they target only one approach per measure (either static or dynamic, not both). |
| 63 | + |
| 64 | +### Calculation groups with format expressions |
| 65 | + |
| 66 | +- Calculation groups can define Format String Expressions that override measure formats. If a calc item's format expression is active, the UI may still display the measure's static FormatString, creating the appearance of both being set. |
| 67 | + |
| 68 | +### Version or environment constraints |
| 69 | + |
| 70 | +- Dynamic format strings for measures have limited availability and may not be fully supported in certain Power BI versions or deployment modes (Report Server). |
| 71 | +- If you are on Power BI Desktop prior to 2025 or Power BI Report Server prior to January 2025, dynamic measure formats may not be supported. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## Resolution |
| 76 | + |
| 77 | +The solution depends on whether the measure is **remote** (from SSAS/AAS) or **local** (created in the composite model). |
| 78 | + |
| 79 | +### If the measure is remote (from SSAS/AAS) |
| 80 | + |
| 81 | +This is the most common scenario. Remote measures are owned by the source semantic model. |
| 82 | + |
| 83 | +**Recommended approach:** |
| 84 | + |
| 85 | +1. **Manage formatting in the source model.** Open SSAS/AAS in SQL Server Management Studio or Tabular Editor connected to the source model, and set the formatting there. |
| 86 | + |
| 87 | +2. **If report-specific formatting is required,** create a local "wrapper" measure in your Power BI composite model: |
| 88 | + - Define a new measure in the local model that references the remote measure. |
| 89 | + - Apply the desired format string to the wrapper measure. |
| 90 | + - Use the wrapper measure in your report instead of the remote measure. |
| 91 | + |
| 92 | + **Trade-off:** This approach creates duplicates and adds maintenance overhead, but it is the most reliable way to apply report-specific formatting in a Live connection scenario. |
| 93 | + |
| 94 | +### If the measure is local (created in the composite model) |
| 95 | + |
| 96 | +**For static formatting (most common):** |
| 97 | + |
| 98 | +1. Select the measure in Tabular Editor. |
| 99 | +2. Clear the **Format String Expression** field (set it to empty/null). |
| 100 | +3. Set the measure's **Format String** to the desired static format (e.g., `"0.00%"` for percentage, `"$#,##0.00"` for currency). |
| 101 | +4. Save the model. |
| 102 | + |
| 103 | +**For dynamic formatting:** |
| 104 | + |
| 105 | +1. Select the measure. |
| 106 | +2. Keep or set the **Format String Expression** to your desired DAX expression (this is the only formatting property you should use). |
| 107 | +3. Leave the **Format String** as "Custom" (do not attempt to also set a static format string). |
| 108 | +4. Verify that your environment supports dynamic format strings (Power BI Desktop 2025 or later, or Power BI Report Server January 2025 or later). |
| 109 | + |
| 110 | +--- |
| 111 | + |
| 112 | +## Quick Troubleshooting Checklist |
| 113 | + |
| 114 | +- [ ] **Determine measure ownership**: Is the measure remote (SSAS/AAS) or local (composite model)? |
| 115 | +- [ ] **Check Format String Expression**: Even if you didn't set it, verify whether it is populated. In the property grid, look for a non-empty "Format String Expression" field. |
| 116 | +- [ ] **Review scripts and rules**: If you use C# scripts or BPA rules to set measure formats, ensure they do not set both FormatString and Format String Expression in the same pass. |
| 117 | +- [ ] **Check calculation groups**: Confirm whether any calculation group items define a Format String Expression that might be overriding or conflicting with the measure's format. |
| 118 | +- [ ] **Verify environment version**: Confirm your Power BI Desktop (2025 or later) or Power BI Report Server (January 2025 or later) version, especially if using dynamic formats. |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +## Step-by-Step Examples |
| 123 | + |
| 124 | +### Example 1: Fixing a remote measure with static formatting |
| 125 | + |
| 126 | +**Scenario:** You have a "Sales Amount" measure in the remote SSAS model, and you want it formatted as currency in your Power BI report. |
| 127 | + |
| 128 | +**Steps:** |
| 129 | + |
| 130 | +1. In Tabular Editor, connect directly to the SSAS/AAS model (not to the Power BI composite model). |
| 131 | +2. Navigate to the "Sales Amount" measure. |
| 132 | +3. Set its **Format String** to `"$#,##0.00"`. |
| 133 | +4. Save the model back to SSAS/AAS. |
| 134 | +5. Return to Tabular Editor connected to the Power BI composite model; the formatting should now be inherited. |
| 135 | + |
| 136 | +If formatting still does not appear correct in the report, create a local wrapper measure (see below). |
| 137 | + |
| 138 | +### Example 2: Creating a wrapper measure for report-specific formatting |
| 139 | + |
| 140 | +**Scenario:** You need the Sales Amount measure from SSAS formatted differently in this specific report. |
| 141 | + |
| 142 | +**Steps:** |
| 143 | + |
| 144 | +1. In Tabular Editor, connect to the Power BI composite model. |
| 145 | +2. Create a new measure in a local table (or in the measure table if you have one): |
| 146 | + ``` |
| 147 | + Sales Amount (Formatted) = [Sales Amount] |
| 148 | + ``` |
| 149 | +3. Set the **Format String** of the new measure to your desired format (e.g., `"$#,##0.00"`). |
| 150 | +4. Save the model. |
| 151 | +5. Update your report visuals to use the wrapper measure instead of the original remote measure. |
| 152 | + |
| 153 | +### Example 3: Setting local measure with dynamic formatting |
| 154 | + |
| 155 | +**Scenario:** You have a local measure in the composite model and want to apply conditional formatting based on a threshold. |
| 156 | + |
| 157 | +**Steps:** |
| 158 | + |
| 159 | +1. Select the measure in Tabular Editor. |
| 160 | +2. Ensure **Format String** is empty (do not set a static format). |
| 161 | +3. Set **Format String Expression** to your conditional expression: |
| 162 | + ```dax |
| 163 | + IF( |
| 164 | + [YourMeasure] > 1000, |
| 165 | + "#,##0.00", |
| 166 | + "0.00" |
| 167 | + ) |
| 168 | + ``` |
| 169 | +4. Do **not** also set a static FormatString. |
| 170 | +5. Save the model. |
| 171 | +6. Verify your Power BI version supports dynamic format strings (Desktop 2025+ or PBIRS Jan 2025+). |
| 172 | + |
| 173 | +--- |
| 174 | + |
| 175 | +## Prevention Best Practices |
| 176 | + |
| 177 | +1. **Decide on formatting strategy early**: Determine whether each measure should use static or dynamic formatting and stick to one approach per measure. |
| 178 | + |
| 179 | +2. **Audit remote measures**: Before editing formatting in a composite model, check whether the measure is remote. If so, manage formatting in the source SSAS/AAS model. |
| 180 | + |
| 181 | +3. **Use version-appropriate features**: If you're using dynamic format strings, ensure all relevant environments (Desktop, Report Server, Analysis Services) support them for your Power BI version. |
| 182 | + |
| 183 | +4. **Script defensively**: If you write C# scripts or BPA rules to format measures, separate the logic so you only set one for mat property per measure, and include a guard to check whether the other property is already populated. |
| 184 | + |
| 185 | +5. **Clear Format String Expression when switching to static**: If a measure previously used dynamic formatting, always clear the Format String Expression before attempting to set a static FormatString. |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +## Additional Resources |
| 190 | + |
| 191 | +- **[Microsoft Docs - Measure Format Strings](https://learn.microsoft.com/en-us/analysis-services/tmsl/measures-object-tmsl)**: Official documentation on measure formatting in the Tabular Object Model. |
| 192 | +- **[Composite Models in Power BI](https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-composite-models)**: Understanding Live connections and composite model architecture. |
| 193 | +- **[Dynamic Format Strings](https://learn.microsoft.com/en-us/power-bi/create-reports/desktop-dynamic-format-strings)**: Feature availability and usage guidance. |
| 194 | + |
| 195 | +--- |
| 196 | + |
| 197 | +## Still Need Help? |
| 198 | + |
| 199 | +If the steps above don't resolve your issue: |
| 200 | + |
| 201 | +1. **Verify the measure is local**: Connect directly to your Power BI file (.pbix) in Tabular Editor to confirm the measure is defined locally, not remotely. |
| 202 | + |
| 203 | +2. **Export diagnostic information**: Run the following Tabular Editor script to audit all measures: |
| 204 | + ```csharp |
| 205 | + var measures = Model.AllMeasures; |
| 206 | + foreach (var m in measures) |
| 207 | + { |
| 208 | + var hasStaticFormat = !string.IsNullOrEmpty(m.FormatString); |
| 209 | + var hasDynamicFormat = !string.IsNullOrEmpty(m.FormatStringExpression); |
| 210 | + if (hasStaticFormat && hasDynamicFormat) |
| 211 | + { |
| 212 | + Output($"CONFLICT - {m.Name}: FormatString='{m.FormatString}', Expression='{m.FormatStringExpression}'"); |
| 213 | + } |
| 214 | + else if (hasStaticFormat) |
| 215 | + { |
| 216 | + Output($"STATIC - {m.Name}: '{m.FormatString}'"); |
| 217 | + } |
| 218 | + else if (hasDynamicFormat) |
| 219 | + { |
| 220 | + Output($"DYNAMIC - {m.Name}: '{m.FormatStringExpression}'"); |
| 221 | + } |
| 222 | + } |
| 223 | + ``` |
| 224 | + |
| 225 | +3. **Contact support**: Reach out with the diagnostic output and your Power BI and Tabular Editor version numbers. |
0 commit comments