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
    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