{"record":{"id":"cf56496f717d4b70","repo":"apache/druid","slug":"invalid-parameter-type","errorCode":null,"errorMessage":"Invalid parameter type: ","messagePattern":"Invalid parameter type: ","errorType":"exception","errorClass":"QueryDriver.RequestError","httpStatus":null,"severity":"error","filePath":"extensions-contrib/grpc-query/src/main/java/org/apache/druid/grpc/server/QueryDriver.java","lineNumber":374,"sourceCode":"    }\n    return params;\n  }\n\n  private SqlParameter translateParameter(QueryParameter value)\n  {\n    switch (value.getValueCase()) {\n      case DOUBLEVALUE:\n        return new SqlParameter(SqlType.DOUBLE, value.getDoubleValue());\n      case LONGVALUE:\n        return new SqlParameter(SqlType.BIGINT, value.getLongValue());\n      case STRINGVALUE:\n        return new SqlParameter(SqlType.VARCHAR, value.getStringValue());\n      case NULLVALUE:\n      case VALUE_NOT_SET:\n        return null;\n      case ARRAYVALUE:\n      default:\n        throw new RequestError(\"Invalid parameter type: \" + value.getValueCase().name());\n    }\n  }\n\n  /**\n   * Translate the column schema from the Druid internal form to the gRPC\n   * {@link ColumnSchema} form. Note that since the gRPC response returns the\n   * schema, none of the data formats include a header. This makes the data format\n   * simpler and cleaner.\n   */\n  private Iterable<? extends ColumnSchema> encodeSqlColumns(SqlRowTransformer rowTransformer)\n  {\n    RelDataType rowType = rowTransformer.getRowType();\n    final RowSignature signature = RowSignatures.fromRelDataType(rowType.getFieldNames(), rowType);\n    List<ColumnSchema> cols = new ArrayList<>();\n    for (int i = 0; i < rowType.getFieldCount(); i++) {\n      ColumnSchema col = ColumnSchema.newBuilder()\n                                     .setName(signature.getColumnName(i))\n                                     .setSqlType(rowType.getFieldList().get(i).getType().getSqlTypeName().getName())","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-contrib/grpc-query/src/main/java/org/apache/druid/grpc/server/QueryDriver.java#L356-L392","documentation":"translateParameter converts a gRPC QueryParameter's protobuf Value into a Druid SqlParameter. It handles STRING, and treats NULL_VALUE/VALUE_NOT_SET as null; any other value case (e.g. number, bool, array) hits the default branch and throws RequestError(\"Invalid parameter type: ...\"), because the gRPC SQL interface only supports string-typed (VARCHAR) query parameters.","triggerScenarios":"Submitting a gRPC SQL query whose QueryParameter.value is set to a non-string oneof case — e.g. Int32Value, BoolValue, Struct, or ArrayValue — instead of a StringValue (or leaving the case as something other than NULLVALUE/VALUE_NOT_SET).","commonSituations":"Client SDK auto-converts a language number/boolean into a typed protobuf Value instead of wrapping it in a string; hand-built protobuf requests that set a typed field; code generated against a newer request schema passing arrays.","solutions":["Wrap every parameter value as a StringValue in the gRPC request (e.g. Value.newBuilder().setStringValue(\"42\")) and cast in SQL if needed.","For truly NULL parameters, use NULL_VALUE or leave the value unset rather than a typed empty value.","Update the calling code so numbers/booleans are stringified before being placed into QueryParameter.","If array parameters are needed, check the extension version for array support or restructure the SQL to avoid array parameters."],"exampleFix":"// before\nValue v = Value.newBuilder().setInt32Value(42).build();\n// after\nValue v = Value.newBuilder().setStringValue(\"42\").build();","handlingStrategy":"type-guard","validationCode":"// Guard parameter values before building the protobuf request\nstatic boolean isSupportedParamValue(Object v) {\n  return v == null || v instanceof String; // only string/NULL parameters supported\n}","typeGuard":"boolean isStringValue(com.google.protobuf.Value v) {\n  return v.getKindCase() == com.google.protobuf.Value.KindCase.STRING_VALUE\n      || v.getKindCase() == com.google.protobuf.Value.KindCase.NULL_VALUE\n      || v.getKindCase() == com.google.protobuf.Value.KindCase.KIND_NOT_SET;\n}","tryCatchPattern":"try {\n  return stub.query(req);\n} catch (StatusRuntimeException e) {\n  if (e.getStatus().getDescription() != null && e.getStatus().getDescription().startsWith(\"Invalid parameter type\")) {\n    throw new IllegalArgumentException(\"Only VARCHAR (string) and NULL parameters are supported\", e);\n  }\n  throw e;\n}","preventionTips":["Always wrap parameters in Value.newBuilder().setStringValue(...) on the client.","Convert numbers/booleans to strings in client code before binding parameters.","Add a unit test that builds every query's parameter list through one helper that enforces string values.","Cast inside SQL (CAST(? AS BIGINT)) rather than sending typed protobuf values."],"tags":["grpc","sql","parameters","protobuf"],"backgroundTag":"type-mismatch","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}