Matching relationship types is cheaper than debugging blank visuals
Blank visuals are often type mismatches, not proof that "DAX is hard." An int64 fact key next to a string dimension key fails quietly. Role-playing dims multiply the blast radius: one bad FK type breaks several relationships that all looked fine in the diagram.
Align gold SQL and TMDL together. Date keys and degenerate dims deserve explicit type standards. Add a CI check for relationship endpoint types. Matching types is cheaper than another afternoon of staring at empty cards.

Figure 1. Blank visuals are often int64-versus-string relationship endpoints, not proof that DAX is hard. Source: Microsoft Learn: understand relationships.

Figure 2. Align gold SQL types and TMDL together, then gate relationship endpoint types in CI. Source: Microsoft Learn: Direct Lake storage.
I learned this on models where every relationship line was drawn and several still did nothing useful at query time. The fix was not a clever measure. It was making the fact's device key and the role-played device dim share a type end to end. The visuals populated like they had been waiting politely.
The core idea
Relationship lines are not active just because the model view shows them. Endpoint types must match, including across role-plays.
Fix the gold column types and the TMDL (or model metadata) in one change set. File-only TMDL edits without a refresh contract still leave old types in the effective model until you follow through. Standards for date keys and degenerate dims prevent local inventiveness. CI should fail mismatched endpoints the same way it fails broken tests.
A model that stays explainable
1. Treat blank visuals as a type mystery first
Before rewriting DAX, inspect relationship endpoint types and sample keys. Confirm whether values would match if types were aligned. Many "filter context" rabbit holes start as int-versus-string. Save DAX archaeology for after types are boring.
2. Inventory role-playing dims as multipliers
Each role-play duplicates risk. List them. Check every FK that points at them. A single stringly typed date role can blank a family of pages. Role-plays are powerful and unforgiving.
3. Change gold and TMDL together
If gold casts a key to int64, the model column must be int64 too, and the dimension must match. Ship SQL and model metadata as one PR when you can. Document the refresh/republish steps when the environment requires them. Half-updated metadata is a time bomb.
4. Standardize date keys and degenerate dims
Pick a rule: int yyyymmdd versus date versus datetime, and stick to it for keys used in relationships. Degenerate dims on facts need the same honesty. Write the standard in the modeling guide so new facts do not invent a fourth approach.
5. Add CI for relationship endpoint types
Parse TMDL or model definition files and assert left/right column types match for each relationship. Fail the build on mismatch. Humans miss these in review when the diagram looks pretty. Machines do not care about pretty.
6. Keep a fixture that proves the relationship filters
Automated model tests or a small DAX query pack should show non-blank results for known keys after publish. Types can match and keys still disagree on content; fixtures catch both classes over time.
Failure modes I design against
DAX-first debugging. Days lost; types still wrong.
Diagram confidence. Lines drawn, types mismatched.
TMDL-only fix. File changed; effective model not refreshed.
Gold-only fix. SQL correct; model still typed as string.
Ad-hoc date key styles. Every fact invents a convention.
No CI. Regressions return with the next "quick" dim.
A practical repair sequence
Identify the blank visual's driving relationship. Dump endpoint types and five sample values from each side. Align types in gold. Align model metadata. Refresh/republish per your stage rules. Re-run the fixture. Only then consider DAX changes. Write down the sequence in the team runbook so the next blank visual does not restart at step zero with fresh panic.
Role-playing checklist worth stealing
For each role (order date, ship date, service date, install date), record the dim table, the fact FK name, and the type. Keep that table in the repo next to TMDL. When someone adds a new role, they add a row. When CI fails, the checklist shows which role drifted. Boring tables beat heroic debugging.
Degenerate keys deserve the same discipline
Invoice numbers and similar degenerate dims often start as strings "because source." If they participate in relationships or role-plays, pick a type and document it. Changing from string to int later rewrites history in painful ways. Prefer aligning to the source contract early, with explicit casts only at the typing boundary you already chose for bronze or gold keys.
Demo risk is a product risk
Blank visuals in a stakeholder demo destroy trust faster than a late feature. Type mismatches are especially cruel because the model view looks complete. A five-minute endpoint-type check before demos is not paranoia. It is release hygiene. Put it on the demo checklist next to row-count smoke tests.
Trade-offs
Strict type standards constrain flexibility. Flexibility here mostly produces blanks. CI parsing TMDL adds pipeline work; it removes production mystery. Coordinating gold and model PRs can feel slower than "just tweak the file." Slower is fine when the alternative is silent filter failure. Fixture maintenance costs time and prevents demos on empty visuals.
What I would put on an ADR
- Relationship endpoint types must match; mismatches are release blockers.
- Gold and TMDL/model metadata for key types change together with a refresh contract.
- Date key and degenerate dim type standards are written and mandatory for new facts.
- CI validates relationship endpoint types in model definitions.
- Role-playing dims are inventoried with FK type rows in repo docs.
- Fixture queries prove non-blank filtering for critical relationships after publish.
Primary references: Power BI relationship and data type guidance, plus TMDL documentation on Microsoft Learn. Pair docs with CI so the standard is enforced where people actually change models.
Closing
Blank visuals are often a type story wearing a DAX costume.
Match endpoint types. Align gold with the model. Standardize keys. Check it in CI. Role-plays stop being haunted, and debugging time returns to actual business logic.
