risingwavelabs/risingwave · error · SinkError::SqlServer
SQL Server table {} permission metadata error
Error message
SQL Server table {} permission metadata error What it means
When validating that the configured SQL Server user may write to the sink table, RisingWave runs a permission-discovery query (SELECT/INSERT/UPDATE/DELETE grants). Any failure executing that permission query is wrapped in this error, again naming the table via `full_object_path()`. This is distinct from error 892: here the query itself failed; the permission result was never evaluated.
Source
Thrown at src/connector/src/sink/sqlserver.rs:660
else {
return Err(query_table_metadata_error());
};
sql_server_table_metadata.push(SqlServerColumnMetadata {
name: normalize_sql_server_column_name(&col_name),
is_pk: col_is_pk != 0,
data_type: data_type.into_owned(),
});
}
Ok(sql_server_table_metadata)
}
async fn validate_sql_server_write_permission(
sql_client: &mut SqlServerClient,
config: &SqlServerConfig,
is_append_only: bool,
) -> Result<()> {
let permission_query_error = || {
SinkError::SqlServer(anyhow!(format!(
"SQL Server table {} permission metadata error",
config.full_object_path()
)))
};
static QUERY_WRITE_PERMISSION: &str = r#"
SELECT
CAST(HAS_PERMS_BY_NAME(@P1, 'OBJECT', 'INSERT') AS int) AS CanInsert,
CAST(HAS_PERMS_BY_NAME(@P1, 'OBJECT', 'UPDATE') AS int) AS CanUpdate,
CAST(HAS_PERMS_BY_NAME(@P1, 'OBJECT', 'DELETE') AS int) AS CanDelete;"#;
let rows = sql_client
.inner_client
.query(QUERY_WRITE_PERMISSION, &[&config.full_object_path()])
.await?
.into_results()
.await?;
let mut rows = rows.into_iter().flatten();
let row = rows.next().ok_or_else(permission_query_error)?;
let mut iter = row.into_iter();View on GitHub (pinned to 6469eb736d)
Solutions
- Grant the sink user permission-metadata read access: `GRANT VIEW DEFINITION TO <user>;` in the target database.
- Confirm connectivity and correct database in the SQL Server URL before creating the sink.
- Manually run the permission query (`SELECT * FROM fn_my_permissions('<schema>.<table>', 'OBJECT')`) as the sink user to see the raw error.
- Check RisingWave logs for the wrapped driver error to distinguish auth vs network causes.
Defensive patterns
Strategy: validation
Validate before calling
-- run as the sink user
SELECT * FROM fn_my_permissions('dbo.orders', 'OBJECT'); Try / catch
// wrap sink validation and classify permission-query failures
if let Err(e) = sink.validate().await {
if e.to_string().contains("permission metadata error") {
log::warn!("cannot read permissions: check VIEW DEFINITION grant");
}
return Err(e);
} Prevention
- Grant VIEW DEFINITION to the sink principal at setup time
- Validate credentials with sqlcmd before sink creation
- Keep the target database consistent between URL and grants
When it happens
Trigger: `validate` -> `validate_sql_server_write_permission` runs its permission-check SQL and the client returns Err: connection failure, malformed query result, insufficient rights to read permission metadata, or driver error.
Common situations: User has rights on the table but cannot query `sys.database_permissions`/`fn_my_permissions`; server restart or transient network drop during sink validation; wrong database in URL so permission views don't exist; restricted login (contained user without VIEW DEFINITION).
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- SQL Server table {} metadata error
- SQL Server user {} lacks required write permission(s) {} on
- {e}
- `{}` must be {}, or {}
- too many column {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/1977a8ecd02d15fa.
Report an issue: GitHub.