apache/druid · error · IOException

Input stream is null

Error message

Input stream is null

What it means

BloomKFilter.deserialize(InputStream) validates its input before parsing the binary bloom filter format and throws IOException('Input stream is null') when given a null stream. The binary format (numHashFunc byte, bitset length int, then longs) cannot be read from a null source, so it fails fast.

Source

Thrown at extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/filter/BloomKFilter.java:163

    dataOutputStream.writeInt(bloomFilter.getBitSet().length);
    for (long value : bloomFilter.getBitSet()) {
      dataOutputStream.writeLong(value);
    }
  }

  /**
   * Deserialize a bloom filter
   * Read a byte stream, which was written by {@linkplain #serialize(OutputStream, BloomKFilter)}
   * into a {@code BloomKFilter}
   *
   * @param in input bytestream
   *
   * @return deserialized BloomKFilter
   */
  public static BloomKFilter deserialize(InputStream in) throws IOException
  {
    if (in == null) {
      throw new IOException("Input stream is null");
    }

    try {
      DataInputStream dataInputStream = new DataInputStream(in);
      int numHashFunc = dataInputStream.readByte();
      int bitsetArrayLen = dataInputStream.readInt();
      long[] data = new long[bitsetArrayLen];
      for (int i = 0; i < bitsetArrayLen; i++) {
        data[i] = dataInputStream.readLong();
      }
      return new BloomKFilter(data, numHashFunc);
    }
    catch (RuntimeException e) {
      IOException io = new IOException("Unable to deserialize BloomKFilter");
      io.initCause(e);
      throw io;
    }
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Check the stream for null before calling deserialize and treat null as 'no filter' (create an empty BloomKFilter(maxNumEntries) instead)
  2. Fix the upstream producer so a valid serialized filter is always stored (empty filter rather than null)
  3. Add logging/assertions where the stream is created to find why it is null

Example fix

// before
BloomKFilter filter = BloomKFilter.deserialize(in); // NPE/IOE when in == null
// after
BloomKFilter filter = (in == null) ? new BloomKFilter(maxNumEntries) : BloomKFilter.deserialize(in);
Defensive patterns

Strategy: type-guard

Validate before calling

// Java guard before deserializing
if (in == null) { return new BloomKFilter(maxNumEntries); } // empty filter fallback

Type guard

static boolean isReadable(InputStream in) { return in != null; }

Try / catch

try {
  return BloomKFilter.deserialize(in);
} catch (IOException e) {
  if ("Input stream is null".equals(e.getMessage())) {
    return new BloomKFilter(maxNumEntries); // treat as no filter
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling BloomKFilter.deserialize(null), e.g. when a lookup/base64-decoded payload or byte source produced null (missing column value, failed decode, unset variable) and the result is passed straight into deserialize.

Common situations: Reading persisted bloom filter payloads from a database/blob store where the row has no filter stored; deserializing an optional JSON field that was absent; wrapping a base64 field that failed to decode and left the stream null.

Related errors


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