apache/beam · error · IllegalStateException
Expected state to be STARTED, but was PENDING
Error message
Expected state to be STARTED, but was PENDING
What it means
AttemptState.checkStarted() asserts that an attempt has actually begun (STARTED) before an operation proceeds. Calling it while the attempt is still PENDING (start() was never invoked) throws IllegalStateException. The Qos framework requires start() to be called — which also reserves budget — before RPC work is attempted.
Source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/firestore/RpcQosImpl.java:202
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");
}
}
}
private abstract class BaseRpcAttempt implements RpcAttempt {
private final Logger logger;
final O11y o11y;
final StatusCodeAwareBackoff backoff;
final Sleeper sleeper;
AttemptState state;
Instant start;
@SuppressWarnings(View on GitHub (pinned to 12126d8942)
Solutions
- Call attempt.start() after newAttempt() and before using the attempt for RPC operations.
- Ensure no early return skips start() between creation and first use of the attempt.
- Use the connector's high-level helpers (e.g. FirestoreV1 write transforms) which manage the attempt lifecycle for you.
- If using checkActive() vs checkStarted() deliberately, switch to checkActive() when PENDING is an acceptable state.
Example fix
// before RpcQos.Attempt attempt = qos.newAttempt(); attempt.checkStarted(); // throws: still PENDING // after RpcQos.Attempt attempt = qos.newAttempt(); attempt.start(); attempt.checkStarted(); // OK
Defensive patterns
Strategy: validation
Validate before calling
// Java: ensure start() was called before checkStarted() RpcQos.Attempt attempt = qos.newAttempt(); attempt.start(); // must precede checkStarted()/RPC use attempt.checkStarted();
Type guard
boolean attemptStarted = false; // track alongside the attempt
boolean readyForRpc(RpcQos.Attempt attempt) {
return attemptStarted;
} Try / catch
try {
attempt.checkStarted();
// perform batched write / RPC
} catch (IllegalStateException e) {
LOG.error("Attempt was not started; call attempt.start() after newAttempt()", e);
} Prevention
- Always call start() immediately after newAttempt().
- Avoid early returns between newAttempt() and start().
- Prefer built-in FirestoreV1 transforms that manage the attempt lifecycle.
When it happens
Trigger: Calling attempt.checkStarted() (or APIs that call it internally, like the write batch path) on an attempt created with qos.newAttempt() but never started with attempt.start().
Common situations: Skipping the start() call when writing custom Firestore sink code; refactoring that removed the start() invocation; early exits between newAttempt() and start() followed by an attempt to use the batch.
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
- Expected state to be PENDING or STARTED, but was COMPLETE_SU
- Expected state to be PENDING or STARTED, but was COMPLETE_ER
- Expected state to be STARTED, but was COMPLETE_SUCCESS
- Error collections cannot be added after Error Handler is clo
- ErrorHandler must be finalized before the output can be retu
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/d2d6cf5e44082593.
Report an issue: GitHub.