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

  1. Grant the sink user permission-metadata read access: `GRANT VIEW DEFINITION TO <user>;` in the target database.
  2. Confirm connectivity and correct database in the SQL Server URL before creating the sink.
  3. Manually run the permission query (`SELECT * FROM fn_my_permissions('<schema>.<table>', 'OBJECT')`) as the sink user to see the raw error.
  4. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/1977a8ecd02d15fa. Report an issue: GitHub.