apache/beam · error · IOException

Client certificates not yet implemented

Error message

Client certificates not yet implemented

What it means

TokenCredentialSerializer.serializeWithType explicitly rejects ClientCertificateCredential, throwing IOException "Client certificates not yet implemented". Serializing certificate-based credentials would require dumping private key material or complex state via reflection, so it is deliberately unimplemented.

Solutions

  1. Switch to ClientSecretCredential with a client secret instead of a certificate.
  2. Use DefaultAzureCredential so the concrete certificate credential is not serialized directly.
  3. Inject the certificate credential at runtime on the worker (e.g. via a credential provider function) rather than serializing it.
  4. Don't persist AzureOptions carrying certificate credentials to templates; rebuild them on the target environment.

Example fix

// before
options.setCredential(new ClientCertificateCredentialBuilder()
    .tenantId(t).clientId(c).pemCertificate(path).build());
// after
options.setCredential(new ClientSecretCredentialBuilder()
    .tenantId(t).clientId(c).clientSecret(secret).build());
Defensive patterns

Strategy: try-catch

Validate before calling

if (credential instanceof ClientCertificateCredential) {
  throw new IllegalStateException("certificate credentials cannot be serialized; use ClientSecretCredential");
}

Type guard

boolean serializable(TokenCredential c) { return !(c instanceof com.azure.identity.ClientCertificateCredential); }

Try / catch

try {
  exportTemplate(options);
} catch (IOException e) {
  if (e.getMessage().contains("Client certificates not yet implemented")) {
    throw new IllegalStateException("reconfigure with ClientSecretCredential or DefaultAzureCredential");
  }
  throw e;
}

Prevention

When it happens

Trigger: Saving a pipeline or serializing AzureOptions whose credential is a ClientCertificateCredential (built with ClientCertificateCredentialBuilder); template export or job submission that triggers Jackson serialization of the options.

Common situations: Organizations using certificate-based service principals (common for stricter AAD policies) submitting Beam pipelines; switching a working secret-based pipeline to certificate auth and then export fails.

Understand the failure class

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/61339ca958262d37. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/io/azure/src/main/java/org/apache/beam/sdk/io/azure/options/AzureModule.java:209

          ClientSecretCredential credential = (ClientSecretCredential) tokenCredential;
          IdentityClient identityClient = (IdentityClient) getMember(credential, "identityClient");
          jsonGenerator.writeStringField(
              AZURE_CLIENT_ID, (String) getMember(identityClient, "clientId"));
          jsonGenerator.writeStringField(
              AZURE_TENANT_ID, (String) getMember(identityClient, "tenantId"));
          jsonGenerator.writeStringField(
              AZURE_CLIENT_SECRET, (String) getMember(credential, "clientSecret"));
        } else if (tokenCredential instanceof ManagedIdentityCredential) {
          ManagedIdentityCredential credential = (ManagedIdentityCredential) tokenCredential;
          Object appServiceMsiCredential = getMember(credential, "appServiceMSICredential");
          IdentityClient identityClient =
              (IdentityClient) getMember(appServiceMsiCredential, "identityClient");
          jsonGenerator.writeStringField(
              AZURE_CLIENT_ID, (String) getMember(identityClient, "clientId"));
        } else if (tokenCredential instanceof EnvironmentCredential) {
          // Do nothing
        } else if (tokenCredential instanceof ClientCertificateCredential) {
          throw new IOException("Client certificates not yet implemented"); // TODO
        } else if (tokenCredential instanceof UsernamePasswordCredential) {
          UsernamePasswordCredential credential = (UsernamePasswordCredential) tokenCredential;
          IdentityClient identityClient = (IdentityClient) getMember(credential, "identityClient");
          jsonGenerator.writeStringField(
              AZURE_CLIENT_ID, (String) getMember(identityClient, "clientId"));
          jsonGenerator.writeStringField(
              AZURE_USERNAME, (String) getMember(credential, "username"));
          jsonGenerator.writeStringField(
              AZURE_PASSWORD, (String) getMember(credential, "password"));
        } else {
          throw new IOException(
              String.format(
                  "Azure credential provider type '%s' is not supported",
                  tokenCredential.getClass().getSimpleName()));
        }
      } catch (IllegalAccessException | NoSuchFieldException e) {
        throw new IOException(
            String.format(

View on GitHub (pinned to 12126d8942)