{"record":{"id":"c6a5c32dd714f875","repo":"apache/druid","slug":"transform-name-s-cannot-be-used-twice","errorCode":null,"errorMessage":"Transform name '%s' cannot be used twice","messagePattern":"Transform name '(.+?)' cannot be used twice","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/transform/TransformSpec.java","lineNumber":62,"sourceCode":"  public static final TransformSpec NONE = new TransformSpec(null, null);\n\n  private final DimFilter filter;\n  private final List<Transform> transforms;\n\n  @JsonCreator\n  public TransformSpec(\n      @JsonProperty(\"filter\") final DimFilter filter,\n      @JsonProperty(\"transforms\") final List<Transform> transforms\n  )\n  {\n    this.filter = filter;\n    this.transforms = transforms == null ? ImmutableList.of() : transforms;\n\n    // Check for name collisions.\n    final Set<String> seen = new HashSet<>();\n    for (Transform transform : this.transforms) {\n      if (!seen.add(transform.getName())) {\n        throw new ISE(\"Transform name '%s' cannot be used twice\", transform.getName());\n      }\n    }\n  }\n\n  @JsonProperty\n  @Nullable\n  public DimFilter getFilter()\n  {\n    return filter;\n  }\n\n  @JsonProperty\n  public List<Transform> getTransforms()\n  {\n    return transforms;\n  }\n\n  public InputSourceReader decorate(InputSourceReader reader)","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/transform/TransformSpec.java#L44-L80","documentation":"TransformSpec's constructor validates that all configured Transform objects have unique names, since transformed columns would otherwise collide ambiguously. If two transforms share a name, this ISE is thrown at spec construction — typically when deserializing an ingestion spec's transformSpec or a query's transformSpec from JSON.","triggerScenarios":"Building/submitting an ingestion task or native query whose transformSpec.transforms list contains two Transform entries with the same name.","commonSituations":"Copy-pasting a transform block in the ingestion spec and forgetting to rename it; programmatically generating transforms where a loop appends duplicate names; merging specs from templates that both define the same transform name.","solutions":["Rename one of the duplicate transforms so each name in the transforms array is unique.","If both transforms compute the same thing, delete the redundant entry and keep one.","If you need both intermediate and final values, give the second transform a distinct name and reference the first by column name in its expression.","Validate the spec JSON before submission (e.g. assert distinct transform names in your tooling)."],"exampleFix":"// before\n\"transforms\": [\n  {\"name\": \"ts\", \"expression\": \"timestamp_parse(raw_ts)\"},\n  {\"name\": \"ts\", \"expression\": \"format(raw_ts)\"}\n]\n// after\n\"transforms\": [\n  {\"name\": \"ts\", \"expression\": \"timestamp_parse(raw_ts)\"},\n  {\"name\": \"ts_formatted\", \"expression\": \"format(raw_ts)\"}\n]","handlingStrategy":"validation","validationCode":"Set<String> names = new HashSet<>();\nfor (Transform t : transformSpec.getTransforms()) {\n    if (!names.add(t.getName())) {\n        throw new IllegalArgumentException(\"Duplicate transform name: \" + t.getName());\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use unique, descriptive names for every transform in a spec.","When templating or merging specs, deduplicate transforms by name before submission.","Add a pre-submit lint step in CI validating Druid ingestion spec JSON."],"tags":["druid","ingestion","transform","config","duplicate"],"backgroundTag":"schema-validation-failed","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}