Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Get Fabric certified for FREE! Don't miss your chance! Learn more

Reply
jbauti10
Helper I
Helper I

RLS Exclusionary Role with NOT PATHCONTAINS() Not Filtering Data

Hi,

 

I'm implementing Row-Level Security in Microsoft Fabric using embedded reports with a custom username string passed via the embed token identity. I have an exclusionary role that should block specific IDs from being visible, but it is showing all data instead of filtering anything out.

 

Setup

I pass a structured pipe-delimited string as `USERPRINCIPALNAME()` via the embed token:

CHALLENGES=5635|5647|5649;;COMMUNITIES=643|648;;EVALUATOR=135543

My exclusionary RLS role on `Challenge Table` parses this string and uses `NOT PATHCONTAINS()` to exclude the listed IDs:

VAR RLSStr = USERPRINCIPALNAME()
VAR StartStr = SEARCH("CHALLENGES=", RLSStr) + LEN("CHALLENGES=")
VAR EndStr = SEARCH(";;COMMUNITIES", RLSStr)
VAR ChallengeStr = MID(RLSStr, StartStr, EndStr - StartStr)
RETURN
NOT PATHCONTAINS(
ChallengeStr,
FORMAT('Challenge Table'[challenge_id], "0")
)

 

What I've confirmed works

I created a calculated column to verify the parsing and matching is working correctly:

Debug PATHCONTAINS =
VAR RLSStr = "CHALLENGES=5635|5647|5649;;COMMUNITIES=643|648;;EVALUATOR=135543"
VAR StartStr = SEARCH("CHALLENGES=", RLSStr) + LEN("CHALLENGES=")
VAR EndStr = SEARCH(";;COMMUNITIES", RLSStr)
VAR ChallengeStr = MID(RLSStr, StartStr, EndStr - StartStr)
RETURN
PATHCONTAINS(ChallengeStr, FORMAT('Challenge Table'[challenge_id], "0"))

This correctly returns `TRUE` for IDs in the list and `FALSE` for everything else. So the string parsing and `PATHCONTAINS` matching are definitely working.

 

Furthermore, when I use the role without `NOT` (i.e. as an inclusionary role), it correctly filters and only shows the IDs in the list. The moment I add `NOT` to make it exclusionary, it stops filtering and shows all data.

 

What I've tried

- Single direction relationship from `Challenge Table` to `idea_table` - exclusionary still shows all data
- Enabling "Apply security filter in both directions" on the relationship - throws this error:
Table 'Challenge Table' is configured for row-level security, introducing constraints
on how security filters are specified. The setting for Security Filter Behavior on
relationship cannot be Both.

- Applying the RLS filter directly on `idea_table` using the same `NOT PATHCONTAINS()` logic - still shows all data

 

Question

Is there a known issue with `NOT PATHCONTAINS()` in RLS roles? Why would removing `NOT` make it work as an inclusionary role, but adding `NOT` causes it to show all data instead of excluding the listed IDs?

 

Thanks in advance!

1 ACCEPTED SOLUTION

Hi @jbauti10 ,

The issue turned out not to be related to Power BI Embedded, but rather to how NOT PATHCONTAINS() behaves inside Row Level Security (RLS). When the identity string parsing returns a blank or unexpected value, PATHCONTAINS() evaluates to FALSE, and wrapping it with NOT makes the overall expression TRUE for every row. As a result, no records get filtered out, which is why the exclusionary role appeared to not work.

 

To fix this, the exclusion logic was rewritten using a more reliable pattern. Instead of relying on NOT PATHCONTAINS(), the pipe delimited values from USERPRINCIPALNAME() were converted into a table, and the filter was applied using NOT (Column IN Table Variable). This approach avoids the evaluation issue and works consistently within RLS. After applying this logic separately to both the Challenge and Community tables under the same role, and properly activating the role using View As - Other user in Power BI Desktop, the filtering worked as expected. With the test identity CHALLENGES=3696|3326;;COMMUNITIES=625;;EVALUATOR=135543, the Challenge table correctly excluded 3696 and 3326 (showing 3324, 3327, 5391, 51418), and the Community table correctly excluded 625 (showing 999999). This confirms that the behavior was due to how NOT PATHCONTAINS() evaluates in RLS, not a defect in embedding or the RLS engine.

 

Please find the attached .pbix file for your reference.

View solution in original post

6 REPLIES 6
v-menakakota
Community Support
Community Support

Hi @jbauti10 ,

Thanks for reaching out to the Microsoft fabric community forum. 

 

You’ve set this up really carefully, and this behaviour is mostly due to how RLS evaluates filters rather than an issue with NOT PATHCONTAINS() itself.

 

When you use PATHCONTAINS() as an inclusion filter, it works because the expression clearly returns TRUE only for the matching IDs, so RLS keeps those rows. But when you wrap it with NOT, the condition can end up evaluating TRUE for most or all rows during RLS evaluation. Since RLS only keeps rows where the rule is TRUE, this can make it look like no filtering is happening.

 

Also remember that RLS rules act as row filters they define which rows are allowed to be visible. Complex exclusion logic (especially with string parsing) can behave differently in RLS compared to a calculated column, even if your debug column looks correct.

 

A more reliable approach is usually to keep the role inclusion-based instead of exclusion-based meaning define which IDs should be visible rather than trying to block specific ones.

 

So this doesn’t look like a Fabric bug, but more like an RLS evaluation nuance when using NOT with dynamic string logic.

 

If I misunderstand your needs or you still have problems on it, please feel free to let us know. 

Best Regards, 

Best Regards, 
Community Support Team

 

Hi  @v-menakakota , 

Thank you for the response, but I don't think this fully addresses the issue I'm seeing.

 

Please correct me if I'm wrong, but you mentioned that NOT PATHCONTAINS() "can end up evaluating TRUE for most or all rows during RLS evaluation," but my calculated column debug test shows the exact opposite. When I use the same DAX expression in a calculated column, it correctly returns:

  • FALSE for IDs that are in the exclusion list
  • TRUE for all other IDs

This is exactly what an exclusionary filter should do, return TRUE for rows that should be visible.

 

The issue is that when this same expression is used in an RLS role, it shows all rows including the ones where the expression returns FALSE in the calculated column. This suggests the RLS engine is either:

  1. Not evaluating the expression correctly in the RLS context
  2. Ignoring FALSE results and showing those rows anyway
  3. Treating the expression differently than it treats the identical calculated column

Maybe I'm missing something here, but additionally, the fact that removing NOT makes it work perfectly as an inclusionary role proves that:

  • The string parsing is correct
  • PATHCONTAINS() is matching correctly
  • The RLS role is being applied
  • Only the NOT operator is causing unexpected behavior

Regarding your suggestion to use inclusion-based roles instead of exclusion-based: this approach is problematic for my use case. The embed token identity username has a 256 character limit. For users with access to most IDs in the system, an inclusion list would easily exceed this limit, while an exclusion list of the few IDs they can't see stays well under 256 characters. This is precisely why I need the exclusionary approach to work.

 

Could you please help me understand why the same DAX expression would return different boolean values in an RLS role versus a calculated column?

 

Thanks!

Juan

Hi  @jbauti10 ,

Please provide sample data that covers your issue or question completely, in a usable format (not as a screenshot).

Do not include sensitive information. Do not include anything that is unrelated to the issue or question.

Please show the expected outcome based on the sample data you provided.

How to provide sample data in the Power BI Forum - Microsoft Fabric Community

 

Thank you.

Hi @v-menakakota ,

 

Please find the sample report with the sample data in the following link.

Sample Data Provided:

The .pbix file contains a semantic model with the following sample data:

  • Challenge IDs in the dataset: 3696, 3326, 3324, 51418, 3327, 5391
  • Community IDs in the dataset: 625, 999999

RLS Configuration:

I have two exclusionary roles configured:

  1. Challenge Access (Exclusionary) - applied to Challenge Table
  2. Community Access (Exclusionary) - applied to Community Table

Both roles parse a structured string passed via USERPRINCIPALNAME() in the format:

CHALLENGES=<ids>;;COMMUNITIES=<ids>;;EVALUATOR=<id>

Test Scenario:

When embedding the report with this identity username:

CHALLENGES=3696|3326;;COMMUNITIES=625;;EVALUATOR=135543

Expected Outcome:

  • Challenge Table should exclude challenge_ids 3696 and 3326, showing only: 3324, 51418, 3327, 5391
  • Community Table should exclude community_id 625, showing only: 999999
  • Any related tables (like idea_table) should be filtered accordingly through the relationships

Actual Outcome:

  • Challenge Table shows ALL 6 challenge IDs: 3696, 3326, 3324, 51418, 3327, 5391 (no filtering occurs)
  • Community Table shows BOTH community IDs: 625, 999999 (no filtering occurs)
  • The exclusionary roles are not filtering out any data

Note: The inclusion-based role works perfectly, only showing the IDs specified in the list. The issue only occurs when using NOT PATHCONTAINS() for exclusionary filtering.

Hi @jbauti10 ,

The issue turned out not to be related to Power BI Embedded, but rather to how NOT PATHCONTAINS() behaves inside Row Level Security (RLS). When the identity string parsing returns a blank or unexpected value, PATHCONTAINS() evaluates to FALSE, and wrapping it with NOT makes the overall expression TRUE for every row. As a result, no records get filtered out, which is why the exclusionary role appeared to not work.

 

To fix this, the exclusion logic was rewritten using a more reliable pattern. Instead of relying on NOT PATHCONTAINS(), the pipe delimited values from USERPRINCIPALNAME() were converted into a table, and the filter was applied using NOT (Column IN Table Variable). This approach avoids the evaluation issue and works consistently within RLS. After applying this logic separately to both the Challenge and Community tables under the same role, and properly activating the role using View As - Other user in Power BI Desktop, the filtering worked as expected. With the test identity CHALLENGES=3696|3326;;COMMUNITIES=625;;EVALUATOR=135543, the Challenge table correctly excluded 3696 and 3326 (showing 3324, 3327, 5391, 51418), and the Community table correctly excluded 625 (showing 999999). This confirms that the behavior was due to how NOT PATHCONTAINS() evaluates in RLS, not a defect in embedding or the RLS engine.

 

Please find the attached .pbix file for your reference.

Hello @v-menakakota ,

 

Thank you for your help. This indeed solves my problem.

 

Best,

Juan

Helpful resources

Announcements
Join our Fabric User Panel

Join our Fabric User Panel

Share feedback directly with Fabric product managers, participate in targeted research studies and influence the Fabric roadmap.

January Power BI Update Carousel

Power BI Monthly Update - January 2026

Check out the January 2026 Power BI update to learn about new features.

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.