apache/beam · error · IllegalStateException

StateBackedIterable expected terminator of 0 or -1 but…

Error message

StateBackedIterable expected terminator of 0 or -1 but received %s.

What it means

StateBackedIterable.decodeToIterable throws this IllegalStateException when the encoded iterable's terminator value is neither 0 (empty) nor -1 (state-backed, fetch via state client). The terminator is an internal wire-format marker, so any other value means the encoded bytes are corrupt or were produced by an incompatible coder version.

Solutions

  1. Verify the data was written by a compatible Beam SDK version
  2. Re-run the bundle/job so the iterable is re-encoded from source data
  3. Check for data corruption in the transport (data channel) and inspect the encoded bytes
  4. Do not manually construct StateBackedIterable-encoded bytes
Defensive patterns

Strategy: validation

Validate before calling

// Before decoding, check data provenance
if (!Objects.equals(beamVersion, expectedWriterVersion)) {
  throw new IllegalStateException("StateBackedIterable data from incompatible Beam version");
}

Prevention

When it happens

Trigger: Decoding a StateBackedIterable whose byte stream contains a terminator int other than 0 or -1 — typically from corrupted data, manual crafting, or a wire format change between Beam versions.

Common situations: Data written by a different Beam version being re-read; corrupted checkpoints/Fn API data streams; custom code that reuses or forks the StateBackedIterable wire format.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/harness/src/main/java/org/apache/beam/fn/harness/state/StateBackedIterable.java:240

    protected Iterable<T> decodeToIterable(List<T> decodedElements) {
      return decodedElements;
    }

    @Override
    protected Iterable<T> decodeToIterable(
        List<T> decodedElements, long terminatorValue, InputStream in) throws IOException {
      if (terminatorValue == -1L) {
        long tokenLength = VarInt.decodeLong(in);
        ByteString token = ByteString.readFrom(ByteStreams.limit(in, tokenLength));
        return new StateBackedIterable<>(
            cache.get(),
            beamFnStateClient,
            instructionId.get(),
            StateKey.newBuilder().setRunner(StateKey.Runner.newBuilder().setKey(token)).build(),
            getElemCoder(),
            decodedElements);
      } else {
        throw new IllegalStateException(
            String.format(
                "StateBackedIterable expected terminator of 0 or -1 but received %s.",
                terminatorValue));
      }
    }

    @Override
    public void encode(Iterable<T> iterable, OutputStream outStream) throws IOException {
      if (!(iterable instanceof StateBackedIterable)) {
        super.encode(iterable, outStream);
        return;
      }

      StateBackedIterable<T> stateBackedIterable = (StateBackedIterable<T>) iterable;

      DataOutputStream dataOutStream = new DataOutputStream(outStream);
      // We don't know the size without traversing it so use a fixed size buffer
      // and encode as many elements as possible into it before outputting the size followed

View on GitHub (pinned to 12126d8942)