{"record":{"id":"61339ca958262d37","repo":"apache/beam","slug":"client-certificates-not-yet-implemented","errorCode":null,"errorMessage":"Client certificates not yet implemented","messagePattern":"Client certificates not yet implemented","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/azure/src/main/java/org/apache/beam/sdk/io/azure/options/AzureModule.java","lineNumber":209,"sourceCode":"          ClientSecretCredential credential = (ClientSecretCredential) tokenCredential;\n          IdentityClient identityClient = (IdentityClient) getMember(credential, \"identityClient\");\n          jsonGenerator.writeStringField(\n              AZURE_CLIENT_ID, (String) getMember(identityClient, \"clientId\"));\n          jsonGenerator.writeStringField(\n              AZURE_TENANT_ID, (String) getMember(identityClient, \"tenantId\"));\n          jsonGenerator.writeStringField(\n              AZURE_CLIENT_SECRET, (String) getMember(credential, \"clientSecret\"));\n        } else if (tokenCredential instanceof ManagedIdentityCredential) {\n          ManagedIdentityCredential credential = (ManagedIdentityCredential) tokenCredential;\n          Object appServiceMsiCredential = getMember(credential, \"appServiceMSICredential\");\n          IdentityClient identityClient =\n              (IdentityClient) getMember(appServiceMsiCredential, \"identityClient\");\n          jsonGenerator.writeStringField(\n              AZURE_CLIENT_ID, (String) getMember(identityClient, \"clientId\"));\n        } else if (tokenCredential instanceof EnvironmentCredential) {\n          // Do nothing\n        } else if (tokenCredential instanceof ClientCertificateCredential) {\n          throw new IOException(\"Client certificates not yet implemented\"); // TODO\n        } else if (tokenCredential instanceof UsernamePasswordCredential) {\n          UsernamePasswordCredential credential = (UsernamePasswordCredential) tokenCredential;\n          IdentityClient identityClient = (IdentityClient) getMember(credential, \"identityClient\");\n          jsonGenerator.writeStringField(\n              AZURE_CLIENT_ID, (String) getMember(identityClient, \"clientId\"));\n          jsonGenerator.writeStringField(\n              AZURE_USERNAME, (String) getMember(credential, \"username\"));\n          jsonGenerator.writeStringField(\n              AZURE_PASSWORD, (String) getMember(credential, \"password\"));\n        } else {\n          throw new IOException(\n              String.format(\n                  \"Azure credential provider type '%s' is not supported\",\n                  tokenCredential.getClass().getSimpleName()));\n        }\n      } catch (IllegalAccessException | NoSuchFieldException e) {\n        throw new IOException(\n            String.format(","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/azure/src/main/java/org/apache/beam/sdk/io/azure/options/AzureModule.java#L191-L227","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\noptions.setCredential(new ClientCertificateCredentialBuilder()\n    .tenantId(t).clientId(c).pemCertificate(path).build());\n// after\noptions.setCredential(new ClientSecretCredentialBuilder()\n    .tenantId(t).clientId(c).clientSecret(secret).build());","handlingStrategy":"try-catch","validationCode":"if (credential instanceof ClientCertificateCredential) {\n  throw new IllegalStateException(\"certificate credentials cannot be serialized; use ClientSecretCredential\");\n}","typeGuard":"boolean serializable(TokenCredential c) { return !(c instanceof com.azure.identity.ClientCertificateCredential); }","tryCatchPattern":"try {\n  exportTemplate(options);\n} catch (IOException e) {\n  if (e.getMessage().contains(\"Client certificates not yet implemented\")) {\n    throw new IllegalStateException(\"reconfigure with ClientSecretCredential or DefaultAzureCredential\");\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["java","azure-credentials","serialization","client-certificate","unimplemented"],"backgroundTag":"method-not-implemented","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}