apache/beam · error · IllegalStateException

Expected state to be PENDING or STARTED, but was COMPLETE_SU

Error message

Expected state to be PENDING or STARTED, but was COMPLETE_SUCCESS

What it means

RpcQosImpl's AttemptState.checkActive() verifies that a Qos attempt is still in progress before it is used. Calling checkActive() on an attempt already marked COMPLETE_SUCCESS is a lifecycle violation, so IllegalStateException is thrown. The Qos budget/scheduler relies on strict state transitions and refuses to operate on finished attempts.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/firestore/RpcQosImpl.java:189

        sampleUpdate.getMillis(),
        1 /* numSignificantBuckets */,
        1 /* numSignificantSamples */,
        Sum.ofLongs());
  }

  private enum AttemptState {
    PENDING,
    STARTED,
    COMPLETE_SUCCESS,
    COMPLETE_ERROR;

    public void checkActive() {
      switch (this) {
        case PENDING:
        case STARTED:
          return;
        case COMPLETE_SUCCESS:
          throw new IllegalStateException(
              "Expected state to be PENDING or STARTED, but was COMPLETE_SUCCESS");
        case COMPLETE_ERROR:
          throw new IllegalStateException(
              "Expected state to be PENDING or STARTED, but was COMPLETE_ERROR");
      }
    }

    public void checkStarted() {
      switch (this) {
        case STARTED:
          return;
        case PENDING:
          throw new IllegalStateException("Expected state to be STARTED, but was PENDING");
        case COMPLETE_SUCCESS:
          throw new IllegalStateException("Expected state to be STARTED, but was COMPLETE_SUCCESS");
        case COMPLETE_ERROR:
          throw new IllegalStateException("Expected state to be STARTED, but was COMPLETE_ERROR");
      }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Do not reuse an Attempt after completeSuccessfully(); obtain a new attempt via qos.newAttempt() for each operation.
  2. Check the attempt lifecycle: call checkActive()/checkStarted() only before completion, at the start of each attempt.
  3. Guard concurrent access to the Attempt object with synchronization or restrict it to a single thread.
  4. Update the Beam Firestore connector if this occurs inside library code — it may be a fixed internal bug.

Example fix

// before
RpcQos.Attempt attempt = qos.newAttempt();
attempt.completeSuccessfully();
attempt.checkActive(); // throws
// after
RpcQos.Attempt attempt = qos.newAttempt();
attempt.checkActive();
attempt.completeSuccessfully(); // check before completion only
Defensive patterns

Strategy: try-catch

Validate before calling

// Java: verify attempt is still usable before reuse
if (attemptState == RpcQosImpl.AttemptState.COMPLETE_SUCCESS) {
  attempt = qos.newAttempt(); // create new attempt instead of reusing
}

Type guard

boolean isUsable(RpcQos.Attempt attempt) {
  try { attempt.checkActive(); return true; }
  catch (IllegalStateException e) { return false; }
}

Try / catch

try {
  attempt.checkActive();
  // proceed with RPC
} catch (IllegalStateException e) {
  attempt = qos.newAttempt(); // restart lifecycle on stale attempt
}

Prevention

When it happens

Trigger: Reusing a completed RpcQos.Attempt object after completeSuccessfully() has been called — e.g. calling attempt.checkActive() again, or a write batch / awaitOutOfQuotaNotification flow that re-enters with the same attempt — within Firestore connector pipeline code.

Common situations: Custom DoFn or sink code holding onto a Qos Attempt across retries; concurrent threads completing and re-checking the same attempt; bugs in custom code layered on the Firestore connector internals.

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/57fc1da9d28e13b5. Report an issue: GitHub.