testcontainers/testcontainers-java · error · java.lang.RuntimeException
Can't serialize entry
Error message
Can't serialize entry: ${entry} What it means
KeyValuesStatement.appendArguments serializes each Map.Entry key/value to JSON via Jackson to build a Dockerfile instruction (e.g. ENV/LABEL). If Jackson cannot serialize the key or value, it wraps the JsonProcessingException in a RuntimeException naming the offending entry. This usually means a key/value is not JSON-serializable (e.g. an arbitrary POJO without Jackson support, or an ObjectMapper customization issue).
Solutions
- Inspect the failing entry printed in the message and replace the offending key/value with a plain String (e.g. String.valueOf(value)).
- If you need object serialization, register the required Jackson module (e.g. JavaTimeModule) — configure via the statement's ObjectMapper if exposed.
- Avoid nested/complex objects: flatten your map to Map<String, String> before building the statement.
Example fix
// before
Map<String, Object> env = new HashMap<>();
env.put("CONFIG", myConfigPojo);
new KeyValuesStatement("ENV", env);
// after
Map<String, String> env = new HashMap<>();
env.put("CONFIG", String.valueOf(myConfigPojo));
new KeyValuesStatement("ENV", env); Defensive patterns
Strategy: validation
Validate before calling
for (Map.Entry<?,?> e : env.entrySet()) {
if (!(e.getValue() instanceof String || e.getValue() instanceof Number || e.getValue() instanceof Boolean)) {
throw new IllegalArgumentException("Non-serializable ENV value for key: " + e.getKey());
}
} Type guard
static boolean isJsonSerializable(Object v) {
return v == null || v instanceof String || v instanceof Number || v instanceof Boolean || v instanceof Map || v instanceof List;
} Try / catch
try {
statement.appendArguments(sb);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Can't serialize")) {
log.error("Dockerfile entry not JSON-serializable; flatten map to strings", e);
}
throw e;
} Prevention
- Build key-value maps as Map<String, String> for Dockerfile statements
- Avoid passing POJOs or java.time types into ENV/LABEL values
- Test Dockerfile-building code paths in unit tests
When it happens
Trigger: Calling ImageFromDockerfile (or a DockerfileBuilder ENV/LABEL-style statement) with a Map containing keys or values that Jackson cannot write, e.g. non-trivial objects, nulls in unsupported spots, or exotic types with no serializer.
Common situations: Passing parsed config objects (Map<String, Object> with nested POJOs or Date/Duration types without JavaTimeModule) instead of simple strings into a key-values statement; upgrading Jackson and losing a module; custom types lacking getters.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
- Can't serialize arguments
- Failed to convert arguments into json
- overriding previous mapping for
- Tried to parse Dockerfile at path
- Unable to read Dockerfile at path
AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12).
Data as JSON: /api/errors/cbaac13a90ae42dd.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/testcontainers/images/builder/dockerfile/statement/KeyValuesStatement.java:35
super(type);
this.entries = entries;
}
@Override
public void appendArguments(StringBuilder dockerfileStringBuilder) {
Set<Map.Entry<String, String>> entries = this.entries.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
try {
dockerfileStringBuilder.append(objectMapper.writeValueAsString(entry.getKey()));
dockerfileStringBuilder.append("=");
dockerfileStringBuilder.append(objectMapper.writeValueAsString(entry.getValue()));
} catch (JsonProcessingException e) {
throw new RuntimeException("Can't serialize entry: " + entry, e);
}
if (iterator.hasNext()) {
dockerfileStringBuilder.append(" \\\n\t");
}
}
}
}
View on GitHub (pinned to 8e549514e3)