Hello Community,
I am building a custom app and using Fixtures to sync critical business logic records (e.g., specific Notifications, Workflow States) that must be protected from user modification.
The Setup:
-
We export these records as fixtures with is_standard: 1 to prevent users/System Managers from deleting them in the UI.
-
We use a CI/CD pipeline. When we push code, the Production server pulls the Docker image and runs bench migrate.
The Problem:
When we modify a fixture in the code (e.g., change the email subject) and deploy, bench migrate crashes with:
ValidationError: Cannot edit Standard Notification. To edit, please disable this and duplicate it.
The Question:
How can we maintain is_standard: 1 (to protect data integrity from users) while still allowing bench migrate to update these records via code deployments?
Is there a specific flag or hook we need to set so that bench migrate is treated as a privileged “Installer” that ignores the Standard validation check?
Current Workaround:
We are forced to set is_standard: 0 in our fixtures to make CI/CD pass, but this leaves the records vulnerable to user deletion.
Thanks in advance!
1 Like
Hello @Chandru03 ,
This is expected behavior in Frappe, and you’ve already identified the core issue correctly.
Why this happens
Records with is_standard = 1 are treated as immutable by design.
Frappe enforces this rule not only in the UI, but also during bench migrate, fixtures import, and data sync.
So when a fixture changes (for example, subject or message content of a Notification), Frappe blocks the update with:
Cannot edit Standard Notification
This is intentional. There is no special “installer” or “CI mode” that bypasses this validation.
Important clarification
-
bench migrate is not privileged beyond normal server-side permissions
-
Fixtures are imported using standard ORM logic
-
Standard records are expected to be code-owned and frozen, not versioned like configuration
Recommended approaches (used in real projects)
Option 1 — Use is_standard = 0 + permission locking (recommended)
Instead of relying on is_standard:
-
Keep is_standard = 0
-
Lock records using:
-
Custom permissions (remove delete/write from System Manager)
-
Property Setter to disable delete
-
Custom validation hook (before_delete, before_save)
This allows:
This is the most practical and flexible solution.
Option 2 — Split immutable “definition” from editable “instance”
For things like Notifications or Workflows:
In this model:
This avoids fixture conflicts entirely.
Option 3 — Patch-based updates (advanced)
Instead of modifying fixtures:
Example use case:
This works but increases maintenance overhead.
What is not supported
-
No flag to tell Frappe “ignore is_standard during migrate”
-
No hook to elevate fixture imports
-
No safe way to mutate standard records via fixtures
Any attempt to bypass this usually breaks upgrade safety.
Summary
-
is_standard = 1 means read-only forever
-
Frappe enforces this consistently (by design)
-
CI/CD-friendly setups should not rely on is_standard
-
Use permissions, hooks, or regeneration logic instead
Your current workaround is common — the next step is to replace is_standard with controlled protection, not immutability.