{"record":{"id":"8531a06818326eb5","repo":"apache/beam","slug":"invalid-state-for-rewrite-from-s-to-s-readytoenqueue-s","errorCode":null,"errorMessage":"Invalid state for Rewrite, from=%s, to=%s, readyToEnqueue=%s","messagePattern":"Invalid state for Rewrite, from=(.+?), to=(.+?), readyToEnqueue=(.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcsUtilV1.java","lineNumber":1044,"sourceCode":"    public @Nullable GoogleJsonError getLastError() {\n      return lastError;\n    }\n\n    public GcsPath getFrom() {\n      return from;\n    }\n\n    public GcsPath getTo() {\n      return to;\n    }\n\n    public boolean isMetadataOperation() {\n      return performDelete || from.getBucket().equals(to.getBucket());\n    }\n\n    public void enqueue(BatchInterface batch) throws IOException {\n      if (!readyToEnqueue) {\n        throw new IOException(\n            String.format(\n                \"Invalid state for Rewrite, from=%s, to=%s, readyToEnqueue=%s\",\n                from, to, readyToEnqueue));\n      }\n      if (!performDelete) {\n        batch.queue(rewriteRequest, this);\n        return;\n      }\n      Storage.Objects.Delete deleteRequest =\n          storageClient.objects().delete(from.getBucket(), from.getObject());\n      batch.queue(\n          deleteRequest,\n          new JsonBatchCallback<Void>() {\n            @Override\n            public void onSuccess(Void obj, HttpHeaders responseHeaders) {\n              LOG.debug(\"Successfully deleted {} after moving to {}\", from, to);\n              readyToEnqueue = false;\n              lastError = null;","sourceCodeStart":1026,"sourceCodeEnd":1062,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/google-cloud-platform-core/src/main/java/org/apache/beam/sdk/extensions/gcp/util/GcsUtilV1.java#L1026-L1062","documentation":"GcsUtilV1.Rewrite.enqueue throws this IOException when enqueue() is called on a Rewrite whose internal state flag readyToEnqueue is false. readyToEnqueue is only true after a successful initial rewrite response or a retryable error; it becomes false when the rewrite completes or the source is treated as missing. It is an internal state-machine guard in the GCS copy-with-rewrite helper.","triggerScenarios":"Enqueuing a Rewrite operation after it already completed, after it was marked done (readyToEnqueue=false), or calling enqueue twice on the same Rewrite object.","commonSituations":"Custom code reusing Rewrite objects across batches; driver bugs in iterative rewrite loops that don't re-check readyToEnqueue after each response.","solutions":["Only call enqueue() when readyToEnqueue is true (check the public field first)","Create a new Rewrite object instead of reusing a completed one","Review the rewrite loop so each iteration uses the returned Rewrite result"],"exampleFix":"// before\nrewrite.enqueue(batch); // may throw if already done\n// after\nif (rewrite.readyToEnqueue) {\n  rewrite.enqueue(batch);\n} else {\n  LOG.info(\"Rewrite {} -> {} already finished\", rewrite.from, rewrite.to);\n}","handlingStrategy":"type-guard","validationCode":"if (!rewrite.readyToEnqueue) { throw new IllegalStateException(\"Rewrite already done\"); }","typeGuard":"boolean canEnqueue(GcsUtilV1.Rewrite r) { return r.readyToEnqueue; }","tryCatchPattern":"try {\n  rewrite.enqueue(batch);\n} catch (IOException e) {\n  if (e.getMessage().contains(\"Invalid state for Rewrite\")) {\n    // create a fresh Rewrite or skip\n  } else { throw e; }\n}","preventionTips":["Check readyToEnqueue before each enqueue","Never reuse Rewrite objects after completion","Follow the standard rewrite loop pattern in GcsUtil.copy"],"tags":["gcs","state-machine","copy"],"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-20T03:17:13.778Z"}