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_id

View on GitHub (pinned to 6469eb736d)

Solutions

  1. 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).
  2. Test connectivity from the RisingWave host: `sqlcmd -S <server> -U <user> -P <pass> -d <db>`.
  3. Grant the sink user read access to catalog views (e.g. VIEW DEFINITION / SELECT on sys.columns, sys.indexes) in the target database.
  4. 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

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


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