risingwavelabs/risingwave · error · SinkError::SqlServer
SQL Server table {} metadata error
Error message
SQL Server table {} metadata error What it means
RisingWave's SQL Server sink wraps any failure while querying table metadata (columns, primary-key membership, types) from the downstream SQL Server instance in this error, naming the table via `config.full_object_path()`. The query joins sys.indexes/sys.index_columns (filtered by `pk.is_primary_key = 1`) with column metadata; a failure here means the sink cannot validate its schema against the target table. It can stem from connectivity problems, SQL errors, or a missing/unreachable table.
Source
Thrown at src/connector/src/sink/sqlserver.rs:592
// we should not have more than one redirect, so we'll short-circuit here.
Client::connect(config, tcp.compat_write()).await?
}
Err(e) => return Err(e.into()),
};
Ok(Self {
inner_client: client,
})
}
}
async fn query_sql_server_table_metadata(
sql_client: &mut SqlServerClient,
config: &SqlServerConfig,
) -> Result<Vec<SqlServerColumnMetadata>> {
let mut sql_server_table_metadata = Vec::new();
let query_table_metadata_error = || {
SinkError::SqlServer(anyhow!(format!(
"SQL Server table {} metadata error",
config.full_object_path()
)))
};
// Query primary-key membership through a subquery filtered by `pk.is_primary_key = 1`.
// A column can appear in both the primary-key index and secondary indexes, and a naive
// join from `sys.columns` to all `sys.index_columns` would emit extra index rows or mark
// secondary-index-only columns as PK columns. Keep the PK filter inside the subquery so
// each table column is returned once with `IsPk` set only by the primary-key index.
static QUERY_TABLE_METADATA: &str = r#"
SELECT
col.name AS ColumnName,
CAST(CASE WHEN pk_col.column_id IS NULL THEN 0 ELSE 1 END AS int) AS IsPk,
typ.name AS DataType
FROM
sys.columns col
JOIN
sys.types typ ON typ.user_type_id = col.user_type_idView on GitHub (pinned to 6469eb736d)
Solutions
- Verify the sink's SQL Server URL and full object path (database.schema.table) point to an existing table (run `SELECT 1 FROM <table>` with the same credentials).
- Test connectivity from the RisingWave host: `sqlcmd -S <server> -U <user> -P <pass> -d <db>`.
- Grant the sink user read access to catalog views (e.g. VIEW DEFINITION / SELECT on sys.columns, sys.indexes) in the target database.
- Check RisingWave logs for the underlying driver error wrapped by this anyhow error to pinpoint network vs SQL failure.
Example fix
// before (config with wrong path) CREATE SINK s FROM mv WITH (connector='sqlserver', sqlserver.url='...', table='dbo.orderss'); // after CREATE SINK s FROM mv WITH (connector='sqlserver', sqlserver.url='...', table='dbo.orders');
Defensive patterns
Strategy: validation
Validate before calling
-- run with the sink credentials before CREATE SINK SELECT c.name, c.is_identity FROM sys.columns c JOIN sys.tables t ON t.object_id = c.object_id WHERE t.name = 'orders' AND SCHEMA_NAME(t.schema_id) = 'dbo';
Try / catch
// Rust: match on SinkError::SqlServer and check message contains "metadata error"
match sink.validate().await {
Err(e) if e.to_string().contains("metadata error") => verify_connectivity_and_table(),
Err(e) => return Err(e),
Ok(()) => {},
} Prevention
- Ping SQL Server from the RisingWave host before creating the sink
- Use fully qualified database.schema.table names
- Grant catalog-view read access to the sink user
- Lock downstream schema changes behind coordination with sink ownership
When it happens
Trigger: Calling `validate` or `query_downstream_column_metadata` when the inner SQL query for table/primary-key metadata returns Err: network failure to SQL Server, wrong database/schema/table name in the config, SQL syntax or driver error, or the table not existing.
Common situations: Typo in `database.schema.table` in the sink `sqlserver.url`/table config; table dropped or renamed after sink creation; SQL Server unreachable (firewall, wrong port, TLS mismatch); login lacks permission to read catalog views (sys.*); ODBC/TDS driver misconfiguration.
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 {} permission metadata error
- ClickHouse error: {0}
- SinkError::Postgres(anyhow!(err))
- {e}
- `{}` must be {}, or {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/308a8d908c615368.
Report an issue: GitHub.