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

  1. Inspect the failing entry printed in the message and replace the offending key/value with a plain String (e.g. String.valueOf(value)).
  2. If you need object serialization, register the required Jackson module (e.g. JavaTimeModule) — configure via the statement's ObjectMapper if exposed.
  3. 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

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


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)