Skip to content

@clickhouse/client 1.21.0

New features

  • The tracer API (unreleased, introduced in #776) now follows the OpenTelemetry database semantic conventions and matches the attribute vocabulary of the Rust client (clickhouse-rs); see docs/howto/tracing.md for the documentation. In particular (#828):

    • Spans now carry db.system.name (instead of db.system), server.address + server.port (instead of a combined host:port), clickhouse.request.query_id / clickhouse.request.session_id (instead of clickhouse.query_id / clickhouse.session_id), clickhouse.response.format on query and clickhouse.request.format on insert (instead of clickhouse.format), and db.operation.name + db.collection.name on insert (instead of clickhouse.table).
    • The span status is left unset on success (per the OTEL spec recommendation for client spans, previously set to OK); on failure, the span gets the error.type attribute (the error class name) and, for server-side errors, clickhouse.error.code (the numeric ClickHouse error code).
    • Spans record response-side attributes: db.response.status_code (HTTP status) and, when the X-ClickHouse-Summary header is available, clickhouse.summary.* counters (read_rows, written_rows, etc.).
    • query() now emits two spans: clickhouse.query covers the HTTP request lifetime and ends as soon as the response headers are received; a child clickhouse.query.stream span is handed to the ResultSet and tracks the stream consumption, ending when the response is fully read, closed, or fails - with the final clickhouse.response.decoded_bytes and (for row-streaming) db.response.returned_rows metrics. This separation makes it easy to distinguish the original request duration from a stream that may never end (e.g. tailing a live table).
    • Fixed a span leak in the Web ResultSet.stream() path: if the underlying fetch response stream was aborted (e.g. due to a network error), the clickhouse.query.stream span was never ended. The TransformStream now handles both source-stream aborts and consumer-side cancellations via a cancel callback.
    • The insert span records clickhouse.request.sent_rows for array-based inserts.
  • Added a use_multipart_params_auto client option (default: false). When enabled, query() automatically sends query_params as multipart/form-data body parts (the same mechanism as use_multipart_params) once their URL-encoded length exceeds 4096 characters, avoiding HTTP 414/400 errors from HTTP intermediaries (nginx, AWS ALB, CloudFront) caused by over-long URLs - for example, a large IN list or a high-dimensional vector embedding. Smaller parameter payloads remain in the URL query string, so existing behavior is unchanged unless the threshold is crossed. use_multipart_params: true still forces multipart for all queries regardless of size. This does not change the server's per-value size limit, which is governed by http_max_field_value_size. Supported on both @clickhouse/client and @clickhouse/client-web, and overridable per request via use_multipart_params_auto on query(). Ported from clickhouse-connect#789. (#827)

const client = createClient({ use_multipart_params_auto: true });

await client.query({
  query: "SELECT * FROM events WHERE id IN {ids:Array(UInt64)}",
  // Sent in the URL when small, auto-promoted to the multipart body when large
  query_params: { ids: veryLargeArrayOfIds },
});
  • Added a use_multipart_params client option (default: false). When enabled, query() sends query_params as multipart/form-data body parts (with the SQL moved into a query part) instead of URL query-string entries, avoiding HTTP 400 errors caused by over-long URLs when parameters contain large arrays (25K+ values). All other URL search params (database, query_id, settings, session_id, role) remain in the URL. Supported on both @clickhouse/client and @clickhouse/client-web, and overridable per request via use_multipart_params on query(). (#825)
const client = createClient({ use_multipart_params: true });

await client.query({
  query: "SELECT * FROM events WHERE id IN {ids:Array(UInt64)}",
  query_params: { ids: veryLargeArrayOfIds },
  // Per-request override is also supported:
  // use_multipart_params: false,
});

Bug Fixes

  • The client now checks the X-ClickHouse-Exception-Code response header to detect server errors even when the HTTP status code indicates success. In some scenarios (for example, when an exception occurs while streaming the response progress in headers, or with certain proxy setups), ClickHouse responds with HTTP 200 but sets the X-ClickHouse-Exception-Code header. Previously, such responses were treated as successful, and the exception text could surface as malformed response data; now the request is rejected with a parsed ClickHouseError (with the proper code and type), consistent with non-2xx error responses. This applies to both the Node.js and Web clients. (#554, supersedes #350, related issue: #332)