apache/druid · error · IllegalArgumentException
Must have at least one container
Error message
Must have at least one container
What it means
K8sTaskAdapter throws this IllegalArgumentException when converting a task's PodSpec and finds no containers at all in the pod spec. The adapter must locate the first container to inject the task.json extraction command and strip readiness/liveness/startup probes; without any container it cannot build a valid peon pod. This is a guard against a malformed or empty PodSpec.
Solutions
- Ensure the task's PodSpec (or referenced pod template) declares at least one container, typically the main druid peon container.
- Check the k8s pod template YAML for missing or mis-indented `containers:` entries and re-apply it.
- Verify druid.k8s.task.adapter pod template path configuration points at the correct template file.
- If constructing the task JSON in code, call podSpec.getContainers().add(...) before submitting the task.
Example fix
// before (task pod template YAML)
spec:
restartPolicy: Never
// after
spec:
restartPolicy: Never
containers:
- name: main
image: apache/druid:tag Defensive patterns
Strategy: validation
Validate before calling
// java
if (podSpec.getContainers() == null || podSpec.getContainers().isEmpty()) {
throw new IllegalArgumentException("task pod template must define at least one container");
} Try / catch
// java
try { adapter.fromTask(task); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("Must have at least one container")) {
// fix pod template and re-submit
}
} Prevention
- Always include a `main` container in peon pod templates.
- Validate pod template YAML with kubectl apply --dry-run=server before wiring it into Druid config.
- Add a CI check that parses the pod template and asserts containers is non-empty.
When it happens
Trigger: Calling setupMainContainer (via fromTask/toTask conversion) with a PodSpec whose getContainers() list is empty or null-derived empty, e.g. a task spec or pod template with no containers defined.
Common situations: Custom k8s pod template files (druid-k8s podTemplate or task adapter config) that omit the `containers:` section entirely; YAML indentation mistakes that drop containers; building task JSON programmatically without adding a container.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Could not find container named
- At least one task runner must be enabled
- Failed to create K8s ApiClient instance
- Invalid pod adapter [ ], only pod adapter [ ] can be…
- Invalid pod adapter [ ], only pod adapter [ ] can be…
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/abbe45e03e704a34.
Report an issue: GitHub.
Appendix: source
Thrown at extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapter.java:357
);
}
mainContainer.getEnv().addAll(envVars);
}
protected Container setupMainContainer(
PodSpec podSpec,
PeonCommandContext context,
long containerSize,
String taskContents
) throws JsonProcessingException
{
// prepend the startup task.json extraction command
List<String> mainCommand = Lists.newArrayList("sh", "-c");
// update the command
List<Container> containers = podSpec.getContainers();
Container mainContainer = Iterables.getFirst(containers, null);
if (mainContainer == null) {
throw new IllegalArgumentException("Must have at least one container");
}
// remove probes
mainContainer.setReadinessProbe(null);
mainContainer.setLivenessProbe(null);
mainContainer.setStartupProbe(null);
setupPorts(mainContainer);
addEnvironmentVariables(mainContainer, context, taskContents);
mainContainer.setCommand(mainCommand);
mainContainer.setArgs(Collections.singletonList(Joiner.on(" ").join(context.getCommand())));
mainContainer.setName("main");
ResourceRequirements requirements = getResourceRequirements(
mainContainer.getResources(),
containerSize,
context.getCpuMicroCore()View on GitHub (pinned to 9b90983fd2)