apache/druid · error · NullPointerException

Null worker assignment strategy

Error message

Null worker assignment strategy

What it means

WorkerAssignmentStrategy.fromString is a @JsonCreator that converts a config string to the enum via valueOf(toUpperCase(name)), but it first rejects a null name with NPE 'Null worker assignment strategy'. It is invoked during deserialization of MSQ query/context configuration when the strategy field is present but null (explicit null, not missing).

Solutions

  1. Remove the null-valued key from the query context JSON so the default strategy is used
  2. Set the field to a valid strategy name such as "max" or "autoScale"
  3. In Java, guard with Optional/null-check before calling fromString

Example fix

// before
context.put("maxWorkerAssignmentStrategy", null);
// after
context.remove("maxWorkerAssignmentStrategy"); // omit to use default, or set "max"/"autoScale"
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = context.get("maxWorkerAssignmentStrategy");
if (v == null) { context.remove("maxWorkerAssignmentStrategy"); }
else { WorkerAssignmentStrategy.fromString(v.toString()); }

Type guard

boolean hasStrategy(Map<String, Object> ctx) { Object v = ctx.get("maxWorkerAssignmentStrategy"); return v != null; }

Try / catch

try { return WorkerAssignmentStrategy.fromString(name); } catch (NullPointerException e) { return WorkerAssignmentStrategy.defaultValue(); }

Prevention

When it happens

Trigger: Submitting an MSQ query whose context contains e.g. "maxWorkerAssignmentStrategy": null (or the bound field set to null), or Java code calling WorkerAssignmentStrategy.fromString(null).

Common situations: Query templates built programmatically that set the key to null instead of omitting it; clients that serialize unset optional fields as explicit nulls; migration of older query context JSON.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/c68d1ef98091f1d0. Report an issue: GitHub.

Appendix: source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/kernel/WorkerAssignmentStrategy.java:109

        // To handle cases where the input stage is limited to 1 worker because it is reading 1 giant file, I think it
        // would be better to base the number of workers on the number of rows read by the prior stage, which would
        // allow later stages to fan out when appropriate. However, we're not currently tracking this information
        // in a way that is accessible to the assignment strategy.

        final IntSet inputStages = stageDef.getInputStageNumbers();
        final OptionalInt maxInputStageWorkerCount = inputStages.intStream().map(stageWorkerCountMap).max();
        final int workerCount = Math.min(stageDef.getMaxWorkerCount(), maxInputStageWorkerCount.orElse(1));
        return slicer.sliceStatic(inputSpec, segmentPruner, workerCount);
      }
    }
  };

  @JsonCreator
  public static WorkerAssignmentStrategy fromString(final String name)
  {
    if (name == null) {
      throw new NullPointerException("Null worker assignment strategy");
    }
    return valueOf(StringUtils.toUpperCase(name));
  }

  @Override
  @JsonValue
  public String toString()
  {
    return StringUtils.toLowerCase(name());
  }

  /**
   * @param stageDef current stage definition. Contains information on max workers, input stage numbers
   * @param inputSpec inputSpec containing information on where the input is read from
   * @param stageWorkerCountMap map of past stage number vs number of worker inputs
   * @param slicer creates slices of input spec based on other parameters
   * @param maxInputFilesPerSlice hard maximum number of files per input slice
   * @param maxInputBytesPerSlice maximum suggested bytes per input slice

View on GitHub (pinned to 9b90983fd2)