drizzle-team/drizzle-orm · error · Error
crudPolicy requires a modify policy
Error message
crudPolicy requires a modify policy
What it means
An Error 'crudPolicy requires a modify policy' thrown by crudPolicy() in drizzle-orm/src/neon/rls.ts:25 when options.modify === undefined. crudPolicy needs an explicit modify decision (governing insert/update/delete policies). As with read, null is valid (suppresses the modify policies) — only undefined throws.
Source
Thrown at drizzle-orm/src/neon/rls.ts:25
* Generates a set of PostgreSQL row-level security (RLS) policies for CRUD operations based on the provided options.
*
* @param options - An object containing the policy configuration.
* @param options.role - The PostgreSQL role(s) to apply the policy to. Can be a single `PgRole` instance or an array of `PgRole` instances or role names.
* @param options.read - The SQL expression or boolean value that defines the read policy. Set to `true` to allow all reads, `false` to deny all reads, or provide a custom SQL expression. Set to `null` to prevent the policy from being generated.
* @param options.modify - The SQL expression or boolean value that defines the modify (insert, update, delete) policies. Set to `true` to allow all modifications, `false` to deny all modifications, or provide a custom SQL expression. Set to `null` to prevent policies from being generated.
* @returns An array of PostgreSQL policy definitions, one for each CRUD operation.
*/
export const crudPolicy = (options: {
role: PgPolicyToOption;
read: SQL | boolean | null;
modify: SQL | boolean | null;
}) => {
if (options.read === undefined) {
throw new Error('crudPolicy requires a read policy');
}
if (options.modify === undefined) {
throw new Error('crudPolicy requires a modify policy');
}
let read: SQL | undefined;
if (options.read === true) {
read = sql`true`;
} else if (options.read === false) {
read = sql`false`;
} else if (options.read !== null) {
read = options.read;
}
let modify: SQL | undefined;
if (options.modify === true) {
modify = sql`true`;
} else if (options.modify === false) {
modify = sql`false`;
} else if (options.modify !== null) {
modify = options.modify;View on GitHub (pinned to b7862528fd)
Solutions
- Provide an explicit modify value: true, false, null, or a SQL expression.
- Default modify explicitly when assembling options dynamically.
- Strengthen the config type so TS catches the missing field.
Example fix
// before
crudPolicy({ role: authenticatedRole, read: true });
// throws: crudPolicy requires a modify policy
// after
crudPolicy({ role: authenticatedRole, read: true, modify: true });
// or, to suppress modify policies entirely:
crudPolicy({ role: authenticatedRole, read: true, modify: null }); Defensive patterns
Strategy: validation
Validate before calling
import type { crudPolicy } from 'drizzle-orm/neon';
type CrudOpts = Parameters<typeof crudPolicy>[0];
function assertCrudPolicyOptions(o: CrudOpts): void {
if (o.modify === undefined) {
throw new Error('crudPolicy: set `modify` (true | false | null | SQL). null suppresses modify policies.');
}
}
assertCrudPolicyOptions(opts); Type guard
function hasModifyPolicy(o: { modify?: unknown }): boolean {
return o.modify !== undefined;
} Prevention
- Always pass modify explicitly — use null to suppress modify policies.
- Avoid spreading partial objects into crudPolicy; default both fields deliberately.
- Use strict TypeScript so the missing field is a compile error.
When it happens
Trigger: Calling crudPolicy({ role, read: ... }) and omitting modify. Reaches the guard after the read check passes, so you only see this when read is set but modify is undefined.
Common situations: A read-heavy table where the developer specifies read:true and forgets modify, or builds the options object from a partial. The runtime check enforces an explicit modify decision.
Related errors
- crudPolicy requires a read policy
- No transactions support in neon-http driver
- You have an empty array for "${name}" enum values
- Cannot pass undefined values to any set operator
- values() must be called with at least one value
AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03).
Data as JSON: /data/errors/bce682841453c247.json.
Report an issue: GitHub.