{"id":"bce682841453c247","repo":"drizzle-team/drizzle-orm","slug":"crudpolicy-requires-a-modify-policy","errorCode":null,"errorMessage":"crudPolicy requires a modify policy","messagePattern":"crudPolicy requires a modify policy","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"drizzle-orm/src/neon/rls.ts","lineNumber":25,"sourceCode":" * Generates a set of PostgreSQL row-level security (RLS) policies for CRUD operations based on the provided options.\n *\n * @param options - An object containing the policy configuration.\n * @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.\n * @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.\n * @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.\n * @returns An array of PostgreSQL policy definitions, one for each CRUD operation.\n */\nexport const crudPolicy = (options: {\n\trole: PgPolicyToOption;\n\tread: SQL | boolean | null;\n\tmodify: SQL | boolean | null;\n}) => {\n\tif (options.read === undefined) {\n\t\tthrow new Error('crudPolicy requires a read policy');\n\t}\n\n\tif (options.modify === undefined) {\n\t\tthrow new Error('crudPolicy requires a modify policy');\n\t}\n\n\tlet read: SQL | undefined;\n\tif (options.read === true) {\n\t\tread = sql`true`;\n\t} else if (options.read === false) {\n\t\tread = sql`false`;\n\t} else if (options.read !== null) {\n\t\tread = options.read;\n\t}\n\n\tlet modify: SQL | undefined;\n\tif (options.modify === true) {\n\t\tmodify = sql`true`;\n\t} else if (options.modify === false) {\n\t\tmodify = sql`false`;\n\t} else if (options.modify !== null) {\n\t\tmodify = options.modify;","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-orm/src/neon/rls.ts#L7-L43","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncrudPolicy({ role: authenticatedRole, read: true });\n// throws: crudPolicy requires a modify policy\n\n// after\ncrudPolicy({ role: authenticatedRole, read: true, modify: true });\n// or, to suppress modify policies entirely:\ncrudPolicy({ role: authenticatedRole, read: true, modify: null });","handlingStrategy":"validation","validationCode":"import type { crudPolicy } from 'drizzle-orm/neon';\n\ntype CrudOpts = Parameters<typeof crudPolicy>[0];\n\nfunction assertCrudPolicyOptions(o: CrudOpts): void {\n  if (o.modify === undefined) {\n    throw new Error('crudPolicy: set `modify` (true | false | null | SQL). null suppresses modify policies.');\n  }\n}\n\nassertCrudPolicyOptions(opts);","typeGuard":"function hasModifyPolicy(o: { modify?: unknown }): boolean {\n  return o.modify !== undefined;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["postgres","neon","rls","policy","crud-policy","validation"],"analyzedSha":"b7862528fd8fc39bc2653a6c18dad7c1f4e68d10","analyzedAt":"2026-08-03T18:11:14.318Z","schemaVersion":2}