ERPNext v16 bulk edit not working is almost always one of five things: the Bulk Actions button was relocated in the v16 List View redesign and users think it disappeared, a genuine open bug silently no-ops the date field on some doctypes, a v16 permission regression breaks select-only roles when the bulk action needs to read a linked field, the field you are trying to update is a status button rather than a real field (Sales Order status can't be bulk-changed by design), or your custom has_permission hook returns None on a fall-through path and v16 now reads that as a denial. None of these fixes require touching the database directly.
Bulk edit failures are the least loud kind: no error toast, no console log, the modal closes cleanly and the records look unchanged. Every "the software is broken" ticket in this category we've picked up on v16 traces back to one of the five below. I lead enterprise ERPNext and Frappe implementation programmes at MithTech, a 35-person practice in Bengaluru that designs, customises, integrates and operates business-critical software for manufacturers, distributors, schools, financial services and multi-location operations. This is the diagnostic order we use.
The five causes at a glance
Skimmable summary: cheapest check first — if the button is just moved, everything else is wasted time.
| Symptom | First check | ||
|---|---|---|---|
| 1 | Actions button relocated in v16 List View | Users say "the button disappeared after upgrade" | Ask them to tick a row's checkbox first |
| 2 | Open upstream bug on date fields | Bulk edit accepts input, silently no-ops the date | Try the same on a non-date field; if that works, it's the bug |
| 3 | v16 select-only permission regression | You do not have permission to access field: X in DevTools console | Retry as Administrator — if that works, it's a role issue |
| 4 | Status is a state-machine button, not a field | status is missing from the bulk-edit field picker on Sales/Purchase Order | Look at the field list in Actions → Edit |
| 5 | Custom has_permission returns None on fall-through | Partial: some rows updated, some didn't | grep def has_permission in every custom app for missing return True |
The rest of this post is one section per cause, with the exact fix.
Where did the Bulk Actions button go in ERPNext v16?
Answer
It moved. The v16 List View redesign removed the right sidebar entirely and consolidated bulk operations into an "Actions" button that only appears after at least one row is selected via checkbox. If you never see the button, you have never selected anything — that is the whole bug for a surprisingly large fraction of "bulk edit disappeared in v16" tickets.
Skimmable summary: select a row first, then look at the toolbar row above the list.
The change is documented in the Migrating to version 16 wiki: "Right sidebar removed. Saved filters moved to top. Quick filter customization now user-specific in List View."
If your users are on v16 and cannot find bulk actions:
- In any List View, tick the checkbox in the leftmost column of at least one row.
- Look at the toolbar row above the list (not the sidebar — there is no sidebar anymore).
- The Actions button appears with the count of selected rows next to it. Click it for the bulk operations menu.
If the Actions button never appears even after selection, the problem is not the redesign — walk the rest of the ladder.
Why does bulk edit silently do nothing on the date field?
Skimmable summary: a real, open upstream bug on Delivery Note date. Not your setup.
If you bulk-select Delivery Notes, choose "Edit" from the Actions menu, pick a new date, click Update, and the modal closes without complaint — but the dates on the records are unchanged — you have hit Issue #45881, still open as of this writing. The reproduction:
- Create Delivery Notes in bulk from a Sales Order.
- Select several in the List View.
- Actions → Edit → change the date → Update.
- Refresh the list. Every date is unchanged.
There is no fix in a released version yet. Two workarounds while you wait:
A. Update via the API. From a client script or a small Python script talking to /api/method/frappe.client.set_value:
import frappe
new_date = "2026-09-01"
names = ["DN-2026-00001", "DN-2026-00002", "DN-2026-00003"]
for name in names:
frappe.db.set_value("Delivery Note", name, "posting_date", new_date)
frappe.db.commit()
Run this from bench --site your-site.local console — it bypasses the broken bulk-edit UI entirely.
B. Loop from a Client Script. For non-developers, a List View client script that iterates the current selection and calls frappe.db.set_value per row is the safest route until the upstream fix ships. Keep the batches small (≤50 rows) so a partial failure is easy to reason about.
The same pattern applies if you see the silent no-op on other date fields — the underlying bug appears to be in the bulk-edit dialog's date-field handling, not specific to Delivery Note.
Why do I get "You do not have permission to access field" on v16?
Skimmable summary: v16 tightened select-only permissions and needs explicit read on referenced fields.
The exact error You do not have permission to access field: Employee.status (with any field name) appears on v16 for roles that previously worked. The forum thread on the permission regression traces it to a change in how v16 evaluates select-only permissions: a role granted select on a doctype but not read now cannot resolve link-field lookups that touch other fields of the linked record.
The reported repro is on Manufacturing User assigned select-only on Employee — trying to pick an Employee in a Job Card time log throws the error.
Two clean fixes, pick by intent:
- Grant read on the doctype in question. If the user genuinely should see the linked record's fields,
Selectalone is not enough on v16. Give the roleReadand the error goes away — this is what the migration expects. - Grant read only on the specific referenced field via Perm Level. If the concern is data exposure, keep the doctype at
Selectand use Frappe's per-field permission viapermlevelto grant Read on just the referenced field. More work; genuinely safer.
The forum's suggested workaround of "grant read on Workflow State" is a partial patch — it only works when workflows aren't configured. It is not the general answer.
Why can't I bulk-update Sales Order status?
Skimmable summary: status is a state-machine button, not a database field — by design.
If Actions → Edit does not offer status as an editable field on Sales Order or Purchase Order, that is not a bug — it is Issue #49740. The reason: status on these doctypes is derived from the document's lifecycle (Draft → To Deliver → Completed etc.) and moved through action buttons like Submit, Close, Reopen, Cancel. Directly rewriting status in the database would desynchronise it from docstatus and the child-table state, so the UI refuses.
The workaround for legitimate bulk transitions is a Client Script that calls the correct method per row:
// Bulk "Close" for selected Sales Orders in the List View
frappe.listview_settings['Sales Order'].onload = function(listview) {
listview.page.add_action_item(__("Bulk Close"), function() {
const selected = listview.get_checked_items().map(d => d.name);
if (!selected.length) return;
frappe.confirm(
__("Close {0} selected Sales Orders?", [selected.length]),
() => {
Promise.all(selected.map(name =>
frappe.call({
method: "erpnext.selling.doctype.sales_order.sales_order.close_or_unclose_sales_orders",
args: { names: JSON.stringify([name]), status: "Closed" }
})
)).then(() => {
frappe.show_alert({message: __("Bulk close complete"), indicator: "green"});
listview.refresh();
});
}
);
});
};
The same shape works for Reopen, and for Purchase Order via the equivalent method name. The confirmation dialog and the batch limit are both worth keeping — a bulk-close cannot be undone with one click.
Is your custom has_permission hook silently blocking the bulk action?
Skimmable summary: v16 requires an explicit True return; the fall-through None used to allow, now denies.
Every custom app that added a has_permission hook on v15 has code of this shape:
# your_app/permissions.py
def has_permission(doc, ptype, user):
if some_condition(doc, user):
return True
# implicit None → v15: allowed the bulk action, v16: silently denies
On v16, None is treated as denial. When a user runs Actions → Edit on 30 rows and the hook returns None for even one of them, the bulk operation halts silently at that row and the UI shows no error. The user sees "some rows updated, some didn't" and rightly concludes the bulk edit is broken.
Fix: audit every custom has_permission for missing return statements on the fall-through path. If unrestricted access is the intended fall-through, add return True explicitly. The full change and grep pattern is in the v16 custom-app fix ladder.
What is the diagnostic order for a "bulk edit not working" ticket?
Confirm the user is selecting rows first
Ask the user to send a screenshot after ticking at least one checkbox. If the Actions button appears in the screenshot, the "missing button" was UX confusion, not a bug — end of ticket. If it does not appear after selection, continue.
Reproduce the specific field + doctype
The date-field silent no-op is field-specific and doctype-specific. Ask which doctype and which field. If it matches Issue #45881 (Delivery Note date, and by extension other date fields under the same handler), skip straight to the API workaround — do not spend time debugging your permissions.
Check the browser console
Open DevTools → Console before running the bulk action. A 403 on /api/method/frappe.client.set_value with You do not have permission to access field: X is the v16 select-only permission regression — jump to that section. A silent 200 with no error and no state change is either the date-field bug or a has_permission denial.
Try the same action as Administrator
If Administrator can bulk-edit the same rows successfully, the problem is a permission gap on the user's role — either the v16 select-only regression or a custom has_permission denial. If Administrator also fails, it is the upstream bug or the status-is-a-button case.
Grep custom apps for has_permission with implicit None
For each app in apps/*/permissions.py (and any file referenced by has_permission in hooks.py): grep -n "def has_permission" . then read each function's fall-through. Any function without an explicit return True or return False at the end is a suspect.
Fall back to a client-script or API loop
If the doctype hits the status-is-a-button case or the date-field silent no-op, ship the workaround as a Client Script (users) or a small bench console snippet (admins). Both are safer than trying to force the bulk-edit dialog to do something it cannot.
FAQ
The four questions we field most often on this.
Is ERPNext v16 bulk edit not working across the board, or only on specific fields?
No — bulk edit works for the majority of doctypes and fields on v16. The failures are concentrated in three specific cases: the date-field silent no-op that affects a subset of doctypes, the select-only permission regression that hits roles missing explicit read on referenced fields, and the status-as-button architecture that has always refused direct status writes on Sales Order / Purchase Order. Everything else bulk-edits normally.
Will the date-field bulk edit bug be fixed in a v16 point release?
The issue is open on GitHub as of this writing with no assigned milestone. Watch Issue #45881 for a fix PR — when it merges, the fix lands in the next v16 point release. Until then, plan around the workaround rather than waiting.
Can I add my own bulk actions to the v16 List View?
Yes. The frappe.listview_settings['DocType Name'].onload hook is unchanged from v15 — you can still add_action_item to register a custom bulk action, as the Bulk Close example above shows. The redesigned toolbar picks these up automatically; you do not have to change any wiring for the new UI.
Does the v16 permission regression affect the API too, or just the desk?
The API. The You do not have permission to access field: X error originates in the permission layer, not the UI. A frappe.client.set_value call from a client script, an external system, or a frappe.call inside a doctype form will all raise the same error on a select-only role. The fix — granting explicit read on the referenced field or the whole doctype — resolves both surfaces.
Bulk edit stopped working after your v16 upgrade?
We deploy, customise and operate ERPNext for mid-market operators and multi-entity organisations. If a specific bulk workflow you rely on is silently failing after the v16 upgrade, we can help you identify whether it is a UI change, a permission regression, an upstream bug, or a custom hook — and ship the safe workaround.