Skip to content

io.grpc.StatusRuntimeException: INTERNAL: Encountered end-of-stream mid-frame #103

@shiguixu

Description

@shiguixu
@Override
    public List<Document> searchByVector(List<Float> queryVector, Map<String, Object> kwargs) {
        try {
            float scoreThreshold = (float) kwargs.getOrDefault("score_threshold", 0.0f);
            if (scoreThreshold >= 1.0f) {
                // 如果分数阈值大于等于1,返回空列表
                return new ArrayList<>();
            }
            // 创建过滤器
            Filter.Builder filterBuilder = Filter.newBuilder();

            // 添加 group_id 过滤条件
            filterBuilder.addMust(matchKeyword(Field.GROUP_KEY.getValue(), this.groupId));
            // 如果有文档ID过滤器,则添加
            List<String> documentIdsFilter = (List<String>) kwargs.get("doc_ids_filter");
            if (documentIdsFilter != null && !documentIdsFilter.isEmpty()) {
                filterBuilder.addMust(matchKeywords(Field.DOC_ID.getValue(), documentIdsFilter));
            }
            Filter filter = filterBuilder.build();
            int topK = (int) kwargs.getOrDefault("top_k", 4);
            Points.QueryPoints queryPoints = Points.QueryPoints.newBuilder().setCollectionName(this.collectionName)
                    .setQuery(nearest(queryVector))
                    .setLimit(topK)
                    .setFilter(filter)
                    .setWithPayload(Points.WithPayloadSelector.newBuilder().setEnable(true).build())
                    .build();
            // 执行搜索
            List<Points.ScoredPoint> results = client().queryAsync(queryPoints).get();
            List<Document> docs = new ArrayList<>();
            for (Points.ScoredPoint result : results) {
                if (result.getPayloadMap() == null) {
                    continue;
                }
                // 获取元数据
                buildDocument(result, docs, scoreThreshold);
            }
            // 按分数降序排序
            docs.sort((d1, d2) -> {
                Double score1 = ConverterUtils.toDouble(d1.getMetadata().get(Field.DISTANCE.getValue()), 0.0);
                Double score2 = ConverterUtils.toDouble(d2.getMetadata().get(Field.DISTANCE.getValue()), 0.0);
                return score2.compareTo(score1); // 降序排序
            });
            return docs;
        } catch (Exception e) {
            Throwable cause = e.getCause();
            if (cause instanceof io.grpc.StatusRuntimeException) {
                io.grpc.StatusRuntimeException sre = (io.grpc.StatusRuntimeException) cause;
                log.error("searchByVector failed, gRPC status={}, description={}", sre.getStatus().getCode(), sre.getStatus().getDescription());
                if (sre.getStatus().getCode() != Status.Code.OK) {
                    // 强制重建 client
                    rebuildQdrantClient();
                }
            }
            throw new TranscendBizException(e.getMessage(), e);
        }
    }

public class QdrantVector extends BaseVector {

    private final String collectionName;
    private final String groupId;
    private volatile QdrantClient client;
    private final List<String> attributes;

    private final String distanceFunc = "DOT";

    private final QdrantConfig config;

    public QdrantVector(String collectionName, String groupId, QdrantConfig config, QdrantClient client, List<String> attributes) {
        this.collectionName = collectionName;
        this.groupId = groupId;
        this.config = config;
        this.client = client;
        this.attributes = attributes;
    }

    private QdrantClient client() {
        return this.client;
    }
}
public class QdrantClientConfig {

    @Bean(destroyMethod = "close")
    public QdrantClient qdrantClient(TranAIProperties properties) {
        // 创建 QdrantConfig 配置对象
        QdrantConfig config = new QdrantConfig(
                properties.getQdrantUrl() != null ? properties.getQdrantUrl() : "",
                properties.getQdrantApiKey(),
                properties.getQdrantClientTimeout(),
                properties.getRootPath(),
                properties.getQdrantGrpcPort(),
                properties.getQdrantGrpcEnabled(),
                properties.getQdrantReplicationFactor(),
                null // writeConsistencyFactor 未在原代码中使用,设为 null
        );
        // 1. 先用 NettyChannelBuilder 把 keep-alive 配好
        ManagedChannel channel = ManagedChannelBuilder.forAddress(config.getEndpoint(), config.getGrpcPort())
                .usePlaintext()   // 根据是否启 TLS 决定
                .keepAliveTime(60, TimeUnit.SECONDS)
                .keepAliveTimeout(60, TimeUnit.SECONDS)
                .keepAliveWithoutCalls(true)
                .build();

        QdrantGrpcClient.Builder builder = QdrantGrpcClient
                .newBuilder(channel)
                .withTimeout(Duration.ofSeconds(config.getTimeout()));
        if (config.getApiKey() != null) {
            builder.withApiKey(config.getApiKey());
        }
        return new QdrantClient(builder.build());
    }

}

Version info

Using the latest client (1.16.2) and server (1.16.2)

<dependency>
            <groupId>io.qdrant</groupId>
            <artifactId>client</artifactId>
            <version>1.16.2</version>
        </dependency>
docker run -d --name qdrant \
    -p 6333:6333 -p 6334:6334 \
    -v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
    qdrant/qdrant:v1.16.2

Exception INFO

2026-01-08 14:33:28.442 ERROR 1548 ---  [ault-executor-2] io.qdrant.client.QdrantClient            : Query operation failed

io.grpc.StatusRuntimeException: INTERNAL: Encountered end-of-stream mid-frame
	at io.grpc.Status.asRuntimeException(Status.java:532)
	at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:638)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:565)
	at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:72)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:733)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:714)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)

2026-01-08 14:33:28.443 ERROR 1548 --- 30884aa927948c47390fba60f947d012 [dPool-Thread-73] c.t.t.tranai.vdb.qdrant.QdrantVector     : searchByVector failed, gRPC status=INTERNAL, description=Encountered end-of-stream mid-frame
2026-01-08 14:33:28.443  WARN 1548 --- 30884aa927948c47390fba60f947d012 [dPool-Thread-73] c.t.t.tranai.vdb.qdrant.QdrantVector     : Rebuilding Qdrant client: shutting down old channel...
<==      Total: 0
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7404e3ea]
2026-01-08 14:33:28.458  INFO 1548 ---  [pool-2-thread-1] c.t.f.p.a.b.s.t.RedisTaskProcessorTask   : 数据库中没有等待处理的任务
2026-01-08 14:33:29.572  INFO 1548 --- 30884aa927948c47390fba60f947d012 [dPool-Thread-73] c.t.t.tranai.vdb.qdrant.QdrantVector     : Qdrant client rebuilt successfully
2026-01-08 14:33:36.295 ERROR 1548 ---  [ault-executor-1] io.qdrant.client.QdrantClient            : Query operation failed

io.grpc.StatusRuntimeException: INTERNAL: Encountered end-of-stream mid-frame
	at io.grpc.Status.asRuntimeException(Status.java:532)
	at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:638)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:565)
	at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:72)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:733)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:714)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:750)

2026-01-08 14:33:36.296 ERROR 1548 --- 30884aa927948c47390fba60f947d012 [dPool-Thread-73] c.t.t.tranai.vdb.qdrant.QdrantVector     : searchByVector failed, gRPC status=INTERNAL, description=Encountered end-of-stream mid-frame

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions