{"record":{"id":"9ea83bed166be88a","repo":"risingwavelabs/risingwave","slug":"sql-server-user-lacks-required-write-permission","errorCode":null,"errorMessage":"SQL Server user {} lacks required write permission(s) {} on table {}","messagePattern":"SQL Server user (.+?) lacks required write permission\\(s\\) (.+?) on table (.+?)","errorType":"validation","errorClass":"SinkError::SqlServer","httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/sqlserver.rs","lineNumber":699,"sourceCode":"    };\n    let ColumnData::I32(can_update) = iter.next().ok_or_else(permission_query_error)? else {\n        return Err(permission_query_error());\n    };\n    let ColumnData::I32(can_delete) = iter.next().ok_or_else(permission_query_error)? else {\n        return Err(permission_query_error());\n    };\n\n    let missing_permissions = missing_sql_server_write_permissions(\n        is_append_only,\n        permission_is_granted(can_insert),\n        permission_is_granted(can_update),\n        permission_is_granted(can_delete),\n    );\n    if missing_permissions.is_empty() {\n        return Ok(());\n    }\n\n    Err(SinkError::SqlServer(anyhow!(format!(\n        \"SQL Server user {} lacks required write permission(s) {} on table {}\",\n        config.user,\n        missing_permissions.join(\", \"),\n        config.full_object_path()\n    ))))\n}\n\nfn permission_is_granted(permission_value: Option<i32>) -> bool {\n    permission_value == Some(1)\n}\n\nfn missing_sql_server_write_permissions(\n    is_append_only: bool,\n    can_insert: bool,\n    can_update: bool,\n    can_delete: bool,\n) -> Vec<&'static str> {\n    let mut missing_permissions = vec![];","sourceCodeStart":681,"sourceCodeEnd":717,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/sqlserver.rs#L681-L717","documentation":"After evaluating the permission query, RisingWave compares the grants it found (can_select/insert/update/delete as required by append-only vs upsert mode) against what is needed. If any required permission is missing it throws this error listing the user, the missing permission names joined by commas, and the target table. It is a deliberate preflight check so sinks fail fast instead of erroring mid-stream on write.","triggerScenarios":"`validate` -> `validate_sql_server_write_permission`: the query result shows the configured `config.user` lacks one or more of INSERT/UPDATE/DELETE (and SELECT for upsert) on the table. E.g. an append-only sink without INSERT, or an upsert sink missing UPDATE/DELETE.","commonSituations":"DBA granted permissions to a different login than the one in the sink config; role membership not applied; table owner changed; permissions granted only at schema level with DENY overrides; user created without login mapping.","solutions":["Grant the missing permissions in SQL Server: e.g. `GRANT INSERT, UPDATE, DELETE ON <schema>.<table> TO <user>;` (match what the error lists).","Ensure the user in the sink config is the same principal you granted permissions to (check for login vs user mismatch).","Check for explicit DENY entries overriding grants: `SELECT * FROM sys.database_permissions WHERE grantee_principal_id = USER_ID('<user>')`.","If the sink is append-only, INSERT alone suffices; alternatively switch sink mode to match the permissions actually granted."],"exampleFix":"-- before: user has only SELECT\nGRANT SELECT ON dbo.orders TO rw_sink;\n-- after: grant writes required by an upsert sink\nGRANT SELECT, INSERT, UPDATE, DELETE ON dbo.orders TO rw_sink;","handlingStrategy":"validation","validationCode":"-- preflight: list granted permissions for the sink user\nSELECT permission_name FROM fn_my_permissions('dbo.orders', 'OBJECT')\nWHERE permission_name IN ('SELECT','INSERT','UPDATE','DELETE');","typeGuard":null,"tryCatchPattern":"match sink.validate().await {\n    Err(e) if e.to_string().contains(\"lacks required write permission\") => {\n        request_grants_from_dba(&parse_missing_permissions(&e.to_string()));\n    }\n    other => other,\n}","preventionTips":["Grant SELECT+INSERT (+UPDATE+DELETE for upsert sinks) at provisioning time","Confirm login/user principal name matches the sink config user exactly","Check for DENY overrides when grants seem correct","Automate permission checks in deployment scripts before CREATE SINK"],"tags":["sqlserver","sink","permissions","authorization"],"backgroundTag":"insufficient-permissions","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}