apache/beam · error · NoSuchElementException

The current element is unavailable because either the…

Error message

The current element is unavailable because either the reader is at the beginning of the input and start() or advance() wasn't called, or the last start() or advance() returned false.

What it means

SyntheticBoundedSource's BoundedReader.getCurrent() follows the Beam reader contract: the current element only exists after start() succeeds or advance() returns true. The synthetic source (used by Beam's Nexmark/performance tests to generate deterministic byte payloads) throws NoSuchElementException when getCurrent() is called before the reader is positioned on an element.

Solutions

  1. Call start() once after obtaining the reader, and only call getCurrent()/getCurrentTimestamp() when it returned true.
  2. After each advance(), check its boolean result before reading the current element.
  3. Handle the empty-source case: if start() returns false, treat the source as exhausted and skip reading.

Example fix

// before
BoundedSource.BoundedReader<KV<byte[], byte[]>> r = source.createReader(pipelineOptions);
KV<byte[], byte[]> kv = r.getCurrent();
// after
BoundedSource.BoundedReader<KV<byte[], byte[]>> r = source.createReader(pipelineOptions);
if (r.start()) {
  KV<byte[], byte[]> kv = r.getCurrent();
}
Defensive patterns

Strategy: type-guard

Type guard

boolean hasCurrent(BoundedSource.BoundedReader<?> r) { return r.start() || false; } // only true while start()/advance() returned true

Try / catch

try {
  KV<byte[], byte[]> kv = reader.getCurrent();
} catch (NoSuchElementException e) {
  // reader not positioned or exhausted: call start()/advance() first
}

Prevention

When it happens

Trigger: Calling reader.getCurrent() immediately after createReader() without calling start(); or calling it after advance()/start() returned false (end of input). Typically only hit by custom runner code or tests driving the reader directly.

Common situations: Custom BoundedSource harnesses or unit tests that iterate readers manually and forget the start()/advance() protocol; runners that mis-handle empty synthetic sources where start() returns false immediately.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/9a8c1d24af477e1f. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/io/synthetic/src/main/java/org/apache/beam/sdk/io/synthetic/SyntheticBoundedSource.java:195

      this.readerDelay = new ReaderDelay(source.sourceOptions);
      this.currentKvPair = null;
      this.splitPointFrequencyRecords = source.sourceOptions.splitPointFrequencyRecords;
    }

    @Override
    public synchronized SyntheticBoundedSource getCurrentSource() {
      return (SyntheticBoundedSource) super.getCurrentSource();
    }

    @Override
    protected long getCurrentOffset() throws IllegalStateException {
      return currentOffset;
    }

    @Override
    public KV<byte[], byte[]> getCurrent() throws NoSuchElementException {
      if (currentKvPair == null) {
        throw new NoSuchElementException(
            "The current element is unavailable because either the reader is "
                + "at the beginning of the input and start() or advance() wasn't called, "
                + "or the last start() or advance() returned false.");
      }
      return currentKvPair;
    }

    @Override
    public boolean allowsDynamicSplitting() {
      return splitPointFrequencyRecords > 0;
    }

    @Override
    protected final boolean startImpl() throws IOException {
      this.currentOffset = getCurrentSource().getStartOffset();
      if (splitPointFrequencyRecords > 0) {
        while (currentOffset % splitPointFrequencyRecords != 0) {
          ++currentOffset;

View on GitHub (pinned to 12126d8942)