{"record":{"id":"330483e93a1a26a8","repo":"apache/druid","slug":"lookup-s-has-multiple-segments-cannot-read","errorCode":null,"errorMessage":"Lookup[%s] has multiple segments; cannot read","messagePattern":"Lookup\\[(.+?)\\] has multiple segments; cannot read","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/input/lookup/LookupInputSliceReader.java","lineNumber":88,"sourceCode":"        segmentWrangler.getSegmentsForIntervals(\n            new LookupDataSource(lookupName),\n            Intervals.ONLY_ETERNITY\n        );\n\n    final Iterator<Segment> segmentIterator = segments.iterator();\n    if (!segmentIterator.hasNext()) {\n      throw new ISE(\"Lookup[%s] is not loaded\", lookupName);\n    }\n\n    final Segment segment = segmentIterator.next();\n    if (segmentIterator.hasNext()) {\n      // LookupSegmentWrangler always returns zero or one segments, so this code block can't\n      // happen. That being said: we'll program defensively anyway.\n      CloseableUtils.closeAndSuppressExceptions(\n          segment,\n          e -> log.warn(e, \"Failed to close segment for lookup[%s]\", lookupName)\n      );\n      throw new ISE(\"Lookup[%s] has multiple segments; cannot read\", lookupName);\n    }\n\n    final LoadableSegment loadableSegment = AdaptedLoadableSegment.fromUnmanagedSegment(\n        segment,\n        new SegmentDescriptor(Intervals.ETERNITY, \"0\", 0),\n        StringUtils.format(\"lookup[%s]\", lookupName),\n        counters.channel(CounterNames.inputChannel(inputNumber))\n    );\n\n    return new PhysicalInputSlice(\n        ReadablePartitions.empty(),\n        Collections.singletonList(loadableSegment),\n        Collections.emptyList()\n    );\n  }\n}\n","sourceCodeStart":70,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/input/lookup/LookupInputSliceReader.java#L70-L105","documentation":"LookupSegmentWrangler is contractually expected to return zero or one segment per lookup. attach() defensively closes the segment(s) and throws this ISE if more than one segment is returned, since a lookup snapshot must be a single logical segment.","triggerScenarios":"attach() iterates the wrangler-returned segments and finds a second one - only possible if a custom/nonstandard LookupSegmentWrangler implementation or a misbehaving lookup provider returns multiple segments.","commonSituations":"Custom lookup extension or test wrangler returning multiple published lookup segments; a broken in-memory lookup management layer where lookup updates are both old and new visible simultaneously.","solutions":["Inspect the LookupSegmentWrangler implementation in use and fix it to return at most one segment per lookup.","Ensure lookup updates replace the previous segment atomically rather than publishing an additional one.","Report this as a bug with the lookup provider/extension if you use stock Druid components, since stock behavior guarantees 0 or 1 segments."],"exampleFix":"// before (custom wrangler)\nreturn ImmutableList.of(oldSegment, newSegment);\n// after\nreturn ImmutableList.of(newSegment); // only the latest snapshot","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  reader.attach(buffer);\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"multiple segments\")) {\n    log.error(e, \"LookupSegmentWrangler returned multiple segments\");\n  } else {\n    throw e;\n  }\n}","preventionTips":["Keep custom LookupSegmentWrangler implementations returning at most one segment.","Test lookup update paths for atomic replacement of segments."],"tags":["msq","lookup","defensive-check","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}