apache/beam · error · IOException
Azure credentials provider could not be read.
Error message
Azure credentials provider could not be read.
What it means
AzureModule's TokenCredentialDeserializer.deserializeWithType reads the serialized credential as a Map<String,String>; if the JSON parses to null, it throws IOException "Azure credentials provider could not be read.". This guards the custom Jackson (de)serialization of Azure TokenCredential objects stored in Beam pipeline options.
Source
Thrown at sdks/java/io/azure/src/main/java/org/apache/beam/sdk/io/azure/options/AzureModule.java:100
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
private static class TokenCredentialMixin {}
private static class TokenCredentialDeserializer extends JsonDeserializer<TokenCredential> {
@Override
public TokenCredential deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException {
return context.readValue(jsonParser, TokenCredential.class);
}
@Override
public TokenCredential deserializeWithType(
JsonParser jsonParser, DeserializationContext context, TypeDeserializer typeDeserializer)
throws IOException {
Map<String, String> asMap =
jsonParser.readValueAs(new TypeReference<Map<String, String>>() {});
if (asMap == null) {
throw new IOException("Azure credentials provider could not be read.");
}
String typeNameKey = typeDeserializer.getPropertyName();
String typeName = asMap.get(typeNameKey);
if (typeName == null) {
throw new IOException(
String.format("Azure credentials provider type name key '%s' not found", typeNameKey));
}
if (typeName.equals(DefaultAzureCredential.class.getSimpleName())) {
return new DefaultAzureCredentialBuilder().build();
} else if (typeName.equals(ClientSecretCredential.class.getSimpleName())) {
return new ClientSecretCredentialBuilder()
.clientId(asMap.getOrDefault(AZURE_CLIENT_ID, ""))
.clientSecret(asMap.getOrDefault(AZURE_CLIENT_SECRET, ""))
.tenantId(asMap.getOrDefault(AZURE_TENANT_ID, ""))
.build();
} else if (typeName.equals(ManagedIdentityCredential.class.getSimpleName())) {View on GitHub (pinned to 12126d8942)
Solutions
- Ensure a TokenCredential is actually set on AzureOptions (azureOptions.setCredential(...)) before serialization.
- Inspect the serialized JSON and confirm the credential field is a non-null object with a type-name key.
- Use DefaultAzureCredential when no explicit credential is needed, so a valid object is always serialized.
- Validate pipeline options before launching (e.g. asMap of AzureOptions) to catch null credentials early.
Example fix
// before AzureOptions options = ...; // credential never set -> serialized null // after options.setCredential(new DefaultAzureCredentialBuilder().build());
Defensive patterns
Strategy: validation
Validate before calling
if (azureOptions.getCredential() == null) {
throw new IllegalStateException("AzureOptions.credential must be set before serialization");
} Try / catch
try {
return mapper.readValue(json, TokenCredential.class);
} catch (IOException e) {
if (e.getMessage().contains("could not be read")) {
throw new IllegalStateException("credential payload is null/empty; re-set AzureOptions.credential", e);
}
throw e;
} Prevention
- Always set a TokenCredential on AzureOptions before exporting templates
- Never hand-edit serialized credential JSON
- Validate pipeline options programmatically before launch
- Prefer DefaultAzureCredential so a valid object is always present
When it happens
Trigger: Deserializing pipeline options whose TokenCredential field contains JSON 'null' or an empty/absent value that readValueAs resolves to null; corrupt or hand-edited option payloads missing the credential object.
Common situations: Restoring a saved pipeline/template where the credential field was stripped or null; passing AzureOptions with an unset credential through template-based launches; JSON payloads produced by an older serializer version.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- Azure credentials provider type name key '%s' not found
- Failed to read PipelineOptions from Protocol
- Failed to parse a %s from JSON value: %s
- Azure credential provider type '%s' is not supported
- NullableCoder expects either a byte valued 0 (null) or 1 (pr
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/dc3213b6d5e56e16.
Report an issue: GitHub.