Skip to content

client-v2: Array(Date)/Array(String)/Map query parameters emitted unquoted -> server 400 (CANNOT_PARSE_INPUT_ASSERTION_FAILED) #2897

Description

@polyglotAI-bot

Summary

In client-v2, passing a List/array/Map value as a server-side query parameter emits the inner elements unquoted, so ClickHouse rejects the request. For example a List<LocalDate> bound to {x:Array(Date)} is sent as param_x=[2026-05-13] instead of param_x=['2026-05-13'], and the server returns HTTP 400:

Code: 27. DB::ParsingException: Cannot parse input: expected '\'' before: '2026-05-13]'. (CANNOT_PARSE_INPUT_ASSERTION_FAILED)

Scalar parameters are unaffected (a scalar Date is correctly sent unquoted). Only container parameters — Array(...), Map(...), and nested combinations — whose leaves are String/temporal values are affected.

Root cause

client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java, in addStatementParams:

params.forEach((k, v) -> consumer.accept("param_" + k, String.valueOf(v)));

String.valueOf(List<LocalDate>) calls AbstractCollection.toString(), which formats each element via its own toString() (LocalDate2026-05-13, no quotes) and yields [2026-05-13]. ClickHouse's array text parser for Array(Date) requires single-quoted dates (['2026-05-13']), so it fails. The same applies to Array(String), Array(DateTime), Map(String, Date), and nested containers. Numeric arrays (Array(Int32), Array(Decimal)) must stay unquoted, so the fix must be type-aware, not a blanket quote.

Reproduction

Map<String, Object> params = new HashMap<>();
params.put("l", List.of(LocalDate.now()));
try (QueryResponse r = client.query("SELECT {l:Array(Date)}", params, null).get()) {
    // Expected: returns [today]
    // Actual:   400 CANNOT_PARSE_INPUT_ASSERTION_FAILED (param_l=[2026-05-13])
}

Current workaround: pre-format the value with DataTypeConverter.INSTANCE.arrayToString(list, "Array(Date)") before binding.

Cross-language note

Same bug class as clickhouse-connect issue #188 (Python): a server-side parameter formatter not recursively quoting inner temporal/String values. Root cause is client-side value formatting for the HTTP param_* path, not the wire protocol.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions