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

  1. Ensure the task's PodSpec (or referenced pod template) declares at least one container, typically the main druid peon container.
  2. Check the k8s pod template YAML for missing or mis-indented `containers:` entries and re-apply it.
  3. Verify druid.k8s.task.adapter pod template path configuration points at the correct template file.
  4. 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

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


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)