Skip to content

Regression: checkCompatibility version check runs unauthenticated with withApiKey() (re-breaks #96) #131

Description

@jamesm6162

Summary

The client-server version compatibility check performed in QdrantGrpcClient.Builder.build() is issued without the API key when credentials are configured via withApiKey(...). Against an auth-required server (e.g. Qdrant Cloud) the health check is rejected, and the client logs on every startup:

Failed to obtain server version. Unable to check client-server compatibility. Set checkCompatibility=false to skip version check.

This is a regression of #96, which was fixed in #97 but later undone.

Affected versions

1.18.0 through 1.18.2 (and current master). 1.16.2 and 1.17.0 are not affected.

Root cause

withApiKey(...) no longer sets callCredentials. Since the custom-headers refactor (49e4826, first released in 1.18.0) it only stores the raw apiKey, and the MetadataCredentials are constructed in build() after the compatibility check runs:

public QdrantGrpcClient build() {
  if (checkCompatibility) {
    String clientVersion = Builder.class.getPackage().getImplementationVersion();
    checkVersionsCompatibility(clientVersion);          // (1) runs first
  }

  CallCredentials credentials = this.callCredentials;
  if (credentials == null && (apiKey != null || headers != null)) {
    credentials = new MetadataCredentials(apiKey, headers);   // (2) built afterwards
  }
  ...
}

private void checkVersionsCompatibility(String clientVersion) {
  ...
  QdrantGrpc.newBlockingStub(this.channel)
      .withCallCredentials(this.callCredentials)   // null when only withApiKey() was used
      .healthCheck(...)
  ...
}

The #97 fix worked only because, at the time, withApiKey() set this.callCredentials = new ApiKeyCredentials(apiKey) directly. The custom-headers refactor changed that to defer credential construction, silently re-breaking the check (there was no regression test guarding it).

Reproduction

Build a client against an API-key-protected server (Qdrant Cloud) with the default checkCompatibility=true:

QdrantClient client = new QdrantClient(
    QdrantGrpcClient.newBuilder("xyz.cloud.qdrant.io", 6334, true)
        .withApiKey("<api-key>")
        .build());

The warning is logged at build time. (The resulting client works for normal calls — only the build-time version check is unauthenticated.) The underlying error is PERMISSION_DENIED: HTTP status code 403.

Expected

The compatibility check should use the same credentials the client will use, including the API key provided via withApiKey(...).

Fix

PR incoming: resolve the effective credentials before running the check and pass them into it, plus a regression test. Happy to adjust to your preferences.

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