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
- Switch to ClientSecretCredential with a client secret instead of a certificate.
- Use DefaultAzureCredential so the concrete certificate credential is not serialized directly.
- Inject the certificate credential at runtime on the worker (e.g. via a credential provider function) rather than serializing it.
- 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
- Avoid ClientCertificateCredential in AzureOptions that get persisted
- Inject certificate credentials at runtime on workers instead of serializing
- Prefer DefaultAzureCredential or ClientSecretCredential for templates
- Check credential type before template export in CI
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Azure credential provider type
- Failed to serialize object of type
- Azure credentials provider could not be read.
- Azure credentials provider type name key
- Cannot decode object from input stream.
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)