{"record":{"id":"57fc1da9d28e13b5","repo":"apache/beam","slug":"expected-state-to-be-pending-or-started-but-was-complete","errorCode":null,"errorMessage":"Expected state to be PENDING or STARTED, but was COMPLETE_SUCCESS","messagePattern":"Expected state to be PENDING or STARTED, but was COMPLETE_SUCCESS","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/firestore/RpcQosImpl.java","lineNumber":189,"sourceCode":"        sampleUpdate.getMillis(),\n        1 /* numSignificantBuckets */,\n        1 /* numSignificantSamples */,\n        Sum.ofLongs());\n  }\n\n  private enum AttemptState {\n    PENDING,\n    STARTED,\n    COMPLETE_SUCCESS,\n    COMPLETE_ERROR;\n\n    public void checkActive() {\n      switch (this) {\n        case PENDING:\n        case STARTED:\n          return;\n        case COMPLETE_SUCCESS:\n          throw new IllegalStateException(\n              \"Expected state to be PENDING or STARTED, but was COMPLETE_SUCCESS\");\n        case COMPLETE_ERROR:\n          throw new IllegalStateException(\n              \"Expected state to be PENDING or STARTED, but was COMPLETE_ERROR\");\n      }\n    }\n\n    public void checkStarted() {\n      switch (this) {\n        case STARTED:\n          return;\n        case PENDING:\n          throw new IllegalStateException(\"Expected state to be STARTED, but was PENDING\");\n        case COMPLETE_SUCCESS:\n          throw new IllegalStateException(\"Expected state to be STARTED, but was COMPLETE_SUCCESS\");\n        case COMPLETE_ERROR:\n          throw new IllegalStateException(\"Expected state to be STARTED, but was COMPLETE_ERROR\");\n      }","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/firestore/RpcQosImpl.java#L171-L207","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do not reuse an Attempt after completeSuccessfully(); obtain a new attempt via qos.newAttempt() for each operation.","Check the attempt lifecycle: call checkActive()/checkStarted() only before completion, at the start of each attempt.","Guard concurrent access to the Attempt object with synchronization or restrict it to a single thread.","Update the Beam Firestore connector if this occurs inside library code — it may be a fixed internal bug."],"exampleFix":"// before\nRpcQos.Attempt attempt = qos.newAttempt();\nattempt.completeSuccessfully();\nattempt.checkActive(); // throws\n// after\nRpcQos.Attempt attempt = qos.newAttempt();\nattempt.checkActive();\nattempt.completeSuccessfully(); // check before completion only","handlingStrategy":"try-catch","validationCode":"// Java: verify attempt is still usable before reuse\nif (attemptState == RpcQosImpl.AttemptState.COMPLETE_SUCCESS) {\n  attempt = qos.newAttempt(); // create new attempt instead of reusing\n}","typeGuard":"boolean isUsable(RpcQos.Attempt attempt) {\n  try { attempt.checkActive(); return true; }\n  catch (IllegalStateException e) { return false; }\n}","tryCatchPattern":"try {\n  attempt.checkActive();\n  // proceed with RPC\n} catch (IllegalStateException e) {\n  attempt = qos.newAttempt(); // restart lifecycle on stale attempt\n}","preventionTips":["Never reuse an Attempt after completeSuccessfully().","Create a new attempt per logical operation.","Keep Attempt usage single-threaded or synchronized."],"tags":["firestore","qos","illegal-state","lifecycle","java","apache-beam"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}