{"record":{"id":"8440832c3601a8ee","repo":"prestodb/presto","slug":"pinot-invalid-segment-query-generated-844083","errorCode":"PINOT_INVALID_SEGMENT_QUERY_GENERATED","errorMessage":"Query and segmentsToQuery must be set","messagePattern":"Query and segmentsToQuery must be set","errorType":"error_code","errorClass":"PinotException","httpStatus":null,"severity":"error","filePath":"presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotProxyGrpcRequestBuilder.java","lineNumber":102,"sourceCode":"        return this;\n    }\n\n    public PinotProxyGrpcRequestBuilder addExtraMetadata(Map<String, String> extraMetadata)\n    {\n        this.extraMetadata.putAll(extraMetadata);\n        return this;\n    }\n\n    public PinotProxyGrpcRequestBuilder setSegments(List<String> segments)\n    {\n        this.segments = segments;\n        return this;\n    }\n\n    public Server.ServerRequest build()\n    {\n        if (payloadType == null || segments.isEmpty()) {\n            throw new PinotException(PinotErrorCode.PINOT_INVALID_SEGMENT_QUERY_GENERATED, Optional.empty(), \"Query and segmentsToQuery must be set\");\n        }\n        if (!payloadType.equals(CommonConstants.Query.Request.PayloadType.SQL)) {\n            throw new RuntimeException(\"Only [SQL] Payload type is allowed: \" + payloadType);\n        }\n        Map<String, String> metadata = new HashMap<>();\n        metadata.put(CommonConstants.Query.Request.MetadataKeys.REQUEST_ID, Integer.toString(requestId));\n        metadata.put(CommonConstants.Query.Request.MetadataKeys.BROKER_ID, brokerId);\n        metadata.put(CommonConstants.Query.Request.MetadataKeys.ENABLE_TRACE, Boolean.toString(enableTrace));\n        metadata.put(CommonConstants.Query.Request.MetadataKeys.ENABLE_STREAMING, Boolean.toString(enableStreaming));\n        metadata.put(CommonConstants.Query.Request.MetadataKeys.PAYLOAD_TYPE, payloadType);\n        if (this.hostName != null) {\n            metadata.put(KEY_OF_PROXY_GRPC_FORWARD_HOST, this.hostName);\n        }\n        if (this.port > 0) {\n            metadata.put(KEY_OF_PROXY_GRPC_FORWARD_PORT, String.valueOf(this.port));\n        }\n        extraMetadata.forEach((k, v) -> metadata.put(k, v));\n        return Server.ServerRequest.newBuilder()","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotProxyGrpcRequestBuilder.java#L84-L120","documentation":"PinotProxyGrpcRequestBuilder.build() validates that the request payload type has been set and that at least one segment was supplied before constructing the Server.ServerRequest. If payloadType is null or the segments list is empty, the builder state is incomplete and it throws PinotException with code PINOT_INVALID_SEGMENT_QUERY_GENERATED ('Query and segmentsToQuery must be set').","triggerScenarios":"Using the Pinot gRPC proxy request builder without calling withPayloadType/query (payloadType stays null) or without adding any segments via withSegments/withSegment, then calling build().","commonSituations":"Programmatic use of the Pinot gRPC path where an upstream query-generation step produced zero segments (e.g. table has no segments, or routing returned nothing), or a builder misuse where setters were skipped; integration tests constructing requests manually.","solutions":["Ensure the query was generated successfully and check why segment selection yielded an empty list — verify the table exists in Pinot and has segments (allSegments/online segments).","Call all required builder setters (query/payloadType and segmentsToQuery) before build(); inspect the builder call site for conditional code that skips setters.","If the table is empty or segments are offline, fix Pinot cluster state (reload/upload segments) so the broker returns segments to query.","Guard the build() call: only construct the gRPC request when the generated Pinot query contains at least one segment."],"exampleFix":"// before\nServer.ServerRequest req = new PinotProxyGrpcRequestBuilder(...).build();\n\n// after\nif (segmentsToQuery.isEmpty()) {\n  throw new IllegalStateException(\"No segments selected for table \" + tableName);\n}\nServer.ServerRequest req = new PinotProxyGrpcRequestBuilder(...)\n    .setPayloadType(SQL)\n    .setSegments(segmentsToQuery)\n    .build();","handlingStrategy":"validation","validationCode":"// Validate builder state before build():\nif (payloadType == null) throw new IllegalStateException(\"payloadType not set\");\nif (segmentsToQuery == null || segmentsToQuery.isEmpty()) {\n    throw new IllegalStateException(\"no segments selected for query \" + sql);\n}\nServer.ServerRequest req = builder.build();","typeGuard":"boolean canBuild(PinotProxyGrpcRequestBuilder b) {\n    return b != null && b.hasPayloadType() && b.segmentCount() > 0; // adapt to builder accessors\n}","tryCatchPattern":"try {\n    Server.ServerRequest req = builder.build();\n} catch (PinotException e) {\n    if (PinotErrorCode.PINOT_INVALID_SEGMENT_QUERY_GENERATED.toErrorCodeCode().equals(e.getErrorCode().getName())) {\n        // regenerate the plan or skip gRPC path; fall back to broker HTTP query\n    } else throw e;\n}","preventionTips":["Always call every required builder setter before build()","Check that the target Pinot table has online segments before generating queries","Verify routing/query generation returned a non-empty segment list"],"tags":["pinot","grpc","request-builder","validation"],"backgroundTag":"invalid-request-state","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}