Flow Designer: "The requested flow operation was prohibited by security rules." even with system use

Joatan Fontoura
Tera Guru

Hi there!

I have a flow where I'm having the error "The requested flow operation was prohibited by security rules." in an Update Record action when I try to execute it with a user that doesn't have write permission in the table. As I wrote in the subject, the flow is running as System User. I have a similar issue in a Send Email action: Access denied to create new email.

It looks my flow isn't running with System User even it should. Any ideas?

P.S.: I've already checked this KB: https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0861124

Thank you!

2 ACCEPTED SOLUTIONS

Joatan Fontoura
Tera Guru

Hi there!

Thank you for all your answer. I just solved it creating a copy of the flow (already with flag run as "System User"). I deactivate the original and used the copy. Everything worked fine.

View solution in original post

@Joatan Fontoura 

 

Can you check the link I shared as it explains the same resolution of creating a copy of the flow and disable original flow to fix the issue.

 

https://www.servicenow.com/community/servicenow-ai-platform-forum/why-can-t-i-change-flow-designer-t...

 

As per community guidelines, you can accept more than one answer as accepted solution. If my response helped to answer your query, please mark it helpful & accept the solution.

 

Thanks,

Bhuvan

View solution in original post

8 REPLIES 8

MaxMixali
Giga Guru

ServiceNow – Now Assist Reporting: Access to sys_generative_ai_log, skill-level counting, KPIs & risks

Context
You’re building custom reporting/PA on Now Assist using:
- sys_gen_ai_usage_log (high-level usage/billing)
- sys_generative_ai_log (granular events/steps)

You’re seeing “Security restricted access … rows removed by Security constraints” on sys_generative_ai_log and want to:
1) Know what access is required and how to grant it safely.
2) Confirm if the table lets you count skills/use cases per ticket.
3) Get KPI ideas and understand risks.

------------------------------------------------------------
1) Access to sys_generative_ai_log (why blocked & how to enable)
------------------------------------------------------------
Why you see “Security constraints”:
- That message is raised by row-level “Security Constraints” / Contextual Security rules or restrictive ACLs on the table. Now Assist logs can contain prompts/responses and are intentionally locked down.

How to find the exact requirement in *your* instance:
A. Check ACLs
- System Security → Access Control (ACL)
- Filter Name = sys_generative_ai_log, Type = record, Operation = read
- Inspect “Requires role” and the Script. Also check table.* and parent table ACLs.
- If a role is required (e.g., a specific Now Assist/GenAI admin/viewer role), assign/bundle that role to your reporting role.
- If there’s a script that denies unless a property/role is present, follow its guidance or clone/extend via a separate read ACL that narrows access (e.g., to a specific group).

B. Check “Security constraints” (Contextual Security / Row-level)
- Look for “Security Constraints” modules (if Contextual Security – Advanced is installed).
- Review constraint rules for sys_generative_ai_log that remove rows at list time.
- If present, create a targeted allow rule for a specific group/role (e.g., reporting_analytics), scoping to non-sensitive rows or to time ranges. Avoid blanket allow-all.

C. glide.ui.permitted_tables is not sufficient
- That property only bypasses list-view UI restrictions. It won’t override ACLs or Security Constraints on sys_generative_ai_log.

D. Safer alternative (recommended for analytics)
- Build a read-only **reporting view** or a scheduled **extraction job** that copies a reduced set of columns (e.g., created_on, document, capability/skill, outcome, duration, user, table, record) into a custom log table (u_gen_ai_event_fact).
- Grant report_on/read to that fact table (not the raw log). Mask or drop prompt/response text to avoid PII/exposure.

------------------------------------------------------------
2) Can sys_generative_ai_log support “skills per ticket”?
------------------------------------------------------------
Yes—in most deployments, sys_generative_ai_log holds granular events, such as capability/skill executed (e.g., summarize, suggest_resolution, draft_comment), the target record (table + sys_id), timestamp, actor, and outcome.
Common fields/patterns you may leverage:
- table/document/document_sys_id (target)
- capability/skill/type (the feature invoked)
- user/session/channel (who/how)
- created_on / duration / status (timing & results)

Approach to compute “skills per ticket”:
- Join sys_generative_ai_log to tickets via (table, document/document_sys_id).
- For each ticket (e.g., incident), do COUNT DISTINCT(capability) to get the number of unique use cases executed on that ticket.
- For “average number of use cases per ticket,” aggregate: AVG( distinct_capabilities_per_ticket ).
If you cannot query the table due to constraints, populate u_gen_ai_event_fact nightly with just (ticket, capability, timestamp) and report from there.

------------------------------------------------------------
3) KPI ideas (Adoption, Value, Quality) and PA notes
------------------------------------------------------------
Adoption KPIs
- % Tickets with ≥1 AI use case
- % Agents who used AI this week (DAU/WAU)
- Use case mix: share of summarize / suggest_resolution / draft_comment

Value/Outcome KPIs
- Avg use cases per AI-enabled ticket
- % AI-enabled tickets resolved within SLA vs non-AI tickets
- MTTR delta for AI-enabled vs control group
- Deflection rate (cases resolved without escalation after AI)
- Time saved proxy: sum(duration_saved_estimate) if available, or benchmark-based proxy per skill

Quality/Experience KPIs
- % “Accepted” suggestions vs total suggestions
- Feedback score (thumbs up/down) per skill, per group
- Re-open rate for AI-enabled tickets vs baseline
- Hallucination/flag rate (if tracked)
- Supervisor review adjustments after AI draft usage

Operational KPIs
- Top agents by effective AI usage (accepted ratio, SLA compliance)
- Skills effectiveness by assignment group / domain
- Error/timeout rate per capability and per channel (workspace, portal)

Performance Analytics model
- Indicator sources: use u_gen_ai_event_fact (or sys_* logs if permitted) filtered by table=incident/request/etc.
- Automated Indicators:
- Daily count of tickets with ≥1 AI event
- Daily count of AI events per capability
- Distinct capability count per ticket (rollup to avg)
- Breakdowns: Assignment group, Agent, Capability, Channel, Priority, Category
- Targets/Thresholds: set adoption and quality thresholds per release wave

------------------------------------------------------------
4) Data risks & governance
------------------------------------------------------------
Security/Privacy
- Prompts and responses may include PII or sensitive business context.
- Do NOT grant blanket read access to sys_generative_ai_log.
- Prefer a curated fact table with minimized columns (drop prompt/response text; keep only IDs/metrics).
- Use Data Classification tags and field-level ACLs for any residual text fields.
- Consider column encryption or the Vault if you must keep text.

Performance
- Logs can be high-volume; large ad-hoc queries will be expensive.
- Index by (table, document/document_sys_id, created_on, capability) on analytics table.
- Feed PA from scheduled extracts (daily), not direct live queries on raw logs.
- Implement data retention/archival policies for the raw log table(s).

Auditability
- Maintain a data lineage: source → transformation → analytics fact, with a dictionary entry documenting fields and any masking logic.

------------------------------------------------------------
Actionable checklist
------------------------------------------------------------
[ ] Review ACLs on sys_generative_ai_log (record and table.*) and required roles
[ ] Check for row-level Security Constraints and add a specific allow for your reporting role/group
[ ] If access remains sensitive, build a scheduled extract to u_gen_ai_event_fact with safe columns
[ ] Create PA indicator sources from the fact table; define Adoption, Value, Quality indicators
[ ] Add indexes and retention on the fact table; avoid querying raw logs for dashboards
[ ] Document governance: who can access raw logs, for how long, and why

TL;DR
- Access: blocked by ACL/Contextual Security. Identify required role and/or add a targeted constraint allow; permitted_tables won’t override.
- Skills per ticket: the granular log typically has capability-level events—use it (or a safe extract) to compute distinct skills per ticket and related KPIs.
- Governance: avoid broad read to the raw log; extract only safe fields to a dedicated analytics table and drive PA from there.

MaxMixali
Giga Guru

ServiceNow – Flow Designer says “Run as System User” but Update/Email fail with security errors

Symptom
- Update Record action → “The requested flow operation was prohibited by security rules.”
- Send Email action → “Access denied to create new email.”
- Flow property is set to Run As = System User.

Why this happens
1) Enforce security on the step
Many data actions have an **Advanced → Enforce security** toggle. If enabled, the step evaluates **user ACLs** (the triggering user), even when the Flow property is “Run as System User.” Result: write/insert is blocked.

2) Cross‑scope protection
If the Flow (scope A) updates a table owned by scope B, and scope B’s table **Application Access** does not grant “Can create/update from other application scopes,” the platform blocks it with “prohibited by security rules,” even for System User.

3) Domain separation
System User runs in a given **domain context**. If your record is in another domain and the engine/user domain doesn’t have access, the update is denied.

4) Table‑level protections (sys_email, restricted tables)
Some tables (e.g., **sys_email**) are protected by ACLs and cross‑scope restrictions. “Send Email” creates a sys_email record; with “Enforce security” on (or cross‑scope denied), you’ll see Access denied.

5) Action/subflow overrides
Subflows or specific actions can **override Run As** (e.g., spokes/actions that run “as current”). One secured action in a chain can throw the error.

What to check & how to fix (ordered)
1) Step-level security
- Open the failing **Update Record** (and **Send Email**) step → Advanced.
- **Uncheck “Enforce security.”** Re‑test.
- If this is a Subflow, open the subflow step configuration as well.

2) Cross‑scope application access
- Identify the target table’s **Application scope** (dictionary record).
- In the table definition (in owning app), set **Application access**:
• “Accessible from: All application scopes”
• Check **Can read / Can create / Can update** as needed
- Alternatively, move the Flow into the **same application scope** as the target table.

3) Domain context
- If domain separation is enabled, confirm the Flow Context runs in the correct domain:
• Flow property “Run in the same domain as the trigger” (if available in your release) or
• Add a “Set Flow Context” / domain change step before the update (or run the flow from a BR/event within the correct domain).
- Test with a record in the **same domain** as the executing Flow.

4) Email specifics
- Prefer **Notification → Trigger Event** + OOB Notification, or **Notification → Send Notification** action, rather than writing sys_email yourself.
- If you must use **Send Email (core)**, open step Advanced and **disable Enforce security**.
- Ensure **glide.email.active = true** and SMTP settings are valid in sub‑prod/prod.
- Cross‑scope: sys_email is in Global; your scoped app needs create permission via application access or turn the step to run in a scope that’s allowed.

5) Subflows & spokes
- Open each subflow and action used by the failing step; verify they **don’t override Run As** or have Enforce security toggled on.
- Some spokes run as a **Connection user** (e.g., IntegrationHub). Those do not inherit System User and may require permissions on the remote system, not the instance.

6) Last-resort patterns
- Wrap the change in a **Script step** (server) with a GlideRecord update, executed when the Flow Context is confirmed to be in the right scope/domain.
- Use a lightweight **Business Rule** or **Script Action** (runs as system) triggered by an Event your Flow fires.

Quick diagnostic checklist
- Reproduce in a tiny Flow with just: Trigger → Update Record (same table) → Enforce security OFF.
- From **System Logs → All**, filter by **Source = Flow Engine** and check the exact security message.
- Verify the table’s Application Access and your Flow’s application scope.
- If domain separated, check **current domain** in the execution log (set a temporary Script step: gs.info(gs.getCurrentDomainID())).
- Confirm there’s no Data Policy blocking the insert/update.

Template fixes you can apply now
- Update Record step → Advanced → **uncheck Enforce security**.
- Move Flow to the **owning scope** of the target table (Application picker at top).
- For email, swap to **Trigger Event** + Notification or **Send Notification** (Notification action), not direct sys_email insert.

Summary
- “Run as System User” applies to the **Flow context**, but step‑level **Enforce security**, **cross‑scope**, and **domain** protections still apply.
- Disable Enforce security where appropriate, align application scope, and ensure domain context is correct. For emails, use Notification actions or event‑driven notifications.

MaxMixali
Giga Guru

ServiceNow Flow Designer – “The requested flow operation was prohibited by security rules.”
===========================================================================================

Problem
-------
A Flow with **Run As = System user** fails for certain steps:
- **Update Record** → “The requested flow operation was prohibited by security rules.”
- **Send Email** → “Access denied to create new email.”
When the same Flow is executed by a user without write permissions, it appears the Flow does **not** actually run in system context.

Why this happens
----------------
In Flow Designer, **Run As** is influenced by several layers. Even if the Flow is set to run as **System user**, a step may still enforce ACLs or other security rules due to:

1) **Per‑step security enforcement**
Some core actions (Update, Create, Delete, Look Up, Email) honor a platform property or action‑level setting to **enforce security**. If enforced, the step evaluates ACLs/roles of the **effective user** (which might not be 'system' depending on inheritance).

2) **Run‑as inheritance across Subflows & Actions**
A **Subflow** or **Action** can override the parent Flow’s context:
- Subflow property **“Run As”** may be set to **Caller** instead of **Flow**/**System**.
- Spoke Actions often run **as session user** by default (especially connectors).

3) **Application scope & Protected APIs**
If the Flow or Action resides in a **scoped app with “Enforce Security”**, the engine can still check ACLs even under System. Some tables also have special constraints (scripted ACLs, read‑only states, domain rules).

4) **Domain separation**
With domains enabled, a System context still respects domain visibility. If the target record lives in a different domain (and the Flow runs with a user/domain context that lacks visibility), the Update fails.

5) **Email creation constraints**
The **Send Email** action (writes to `sys_email`) can be restricted by ACLs/props. If a step enforces ACLs and the effective user lacks rights, “Access denied to create new email” is thrown.

How to fix – Checklist
----------------------
A. Confirm run context
1. Open the Flow → **Flow properties** → **Run As: System user** (not “User who triggered”).
2. If calling **Subflows**, open each Subflow:
- Set **Run As** to **System user** or **Use flow caller** (verify which is desired). Prefer **System user** for privileged updates.
3. For **Actions** (custom or spoke), check the **Action properties**:
- Ensure it doesn’t force **“Enforce security”** unless strictly needed.
- If it does, switch to a Script step (see E) for privileged writes.

B. Per‑step security behavior
- In the **Update Record** step, expand **Advanced** and look for any **“Enforce access controls / security”** toggle. Turn it **off** if your governance allows and you truly want system‑level bypass.
- If no toggle exists, replace with a **Script** step (E) to run in true system context.

C. Domain separation
- Confirm the record’s **Domain** vs the Flow’s effective domain.
- If needed, in a Script step: `gs.getSession().setDomainID('<target_domain_sys_id>');` (use with caution).
- Or trigger/run the Flow from a record within the same domain.
- Check properties affecting domain ACLs and whether the **System user** has cross‑domain visibility.

D. Email specifics
- Prefer **Notifications** (sys_notification) and fire them via **Events** (`gs.eventQueue`) instead of raw **Send Email** action when security is tight.
- If you must use **Send Email**, run the action from a **Subflow with Run As = System user**, or replace with a **Script** step that inserts into `sys_email` in system context.
- Verify no ACLs on `sys_email` (or related tables) block creation.

E. Use a Script step (reliable system context)
If governance allows, replace the failing actions with a **Script** step in the same Flow (still Run As System):
```javascript
(function execute(inputs, outputs) {
// Example: update a record with true system context (bypasses ACLs)
var gr = new GlideRecord('target_table');
if (gr.get(inputs.sys_id)) {
gr.setValue('some_field', inputs.new_value);
gr.update(); // uses GlideRecord (not GlideRecordSecure) in system context
}

// Example: queue a notification event instead of Send Email
// gs.eventQueue('my.notification.event', gr, 'parm1', 'parm2');
})(inputs, outputs);
```
Notes:
- In Flow script steps, **GlideRecord** runs as the Flow’s **Run As** principal (System if configured).
- If your organization requires ACL enforcement even in scripts, use **GlideRecordSecure** and ensure the security context has the right roles.

F. Subflow/action inheritance rules
- Ensure **every** layer (Flow → Subflow → Action) has the intended **Run As**. A Subflow set to **Caller** will execute under the **triggering user**, not System.
- Some Spoke steps (e.g., connectors) honor their own **Connection & Credential** and **Use session user** options—configure appropriately.

G. Platform properties to review (names may vary by release)
- Flow Engine security enforcement (global): whether actions enforce ACLs regardless of Run As.
- Email sending restrictions: properties that restrict non‑system inserts into `sys_email`.
- Domain enforcement: ensure the System principal can see/write to the target domain.

H. Prove the context (diagnostics)
- Add a **Script** step before the failing action:
```javascript
(function execute(inputs, outputs) {
gs.info('FLOW DEBUG - user=' + gs.getUserName() + ', role_admin=' + gs.hasRole('admin'));
outputs.ctx_user = gs.getUserName();
})(inputs, outputs);
```
- If you see a non‑system principal, fix Run As inheritance.

Recommended patterns
--------------------
1) **Privileged updates:** Use **Script steps** under **Run As = System user**.
2) **Email:** Prefer **Events + Notifications**; use **Send Email** only if needed and running under a confirmed System context.
3) **Subflows:** Standardize **Run As = System user** for all reusable privileged Subflows.
4) **Least privilege:** If business requires ACL enforcement, keep **Enforce security** ON and grant a **technical role** only to the Flow engine’s context.

Summary
-------
Your error indicates that a step in the Flow is still enforcing ACLs under a non‑system effective user or a restricted domain. Make sure **Run As** is correctly inherited across **Flow/Subflow/Action**, disable per‑step security enforcement (or switch to a **Script step**), and prefer **Events + Notifications** for email. Validate by logging `gs.getUserName()` in a Script step before the failing action.

Joatan Fontoura
Tera Guru

Hi there!

Thank you for all your answer. I just solved it creating a copy of the flow (already with flag run as "System User"). I deactivate the original and used the copy. Everything worked fine.