{"record":{"id":"207a106ef14c87fc","repo":"apache/beam","slug":"error-handler-is-already-closed-and-may-not-be-closed-twice","errorCode":null,"errorMessage":"Error handler is already closed, and may not be closed twice","messagePattern":"Error handler is already closed, and may not be closed twice","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/errorhandling/ErrorHandler.java","lineNumber":145,"sourceCode":"\n    @Override\n    public boolean isClosed() {\n      return closed;\n    }\n\n    @Override\n    public @Nullable OutputT getOutput() {\n      if (!this.isClosed()) {\n        throw new IllegalStateException(\n            \"ErrorHandler must be finalized before the output can be returned\");\n      }\n      return sinkOutput;\n    }\n\n    @Override\n    public void close() {\n      if (closed) {\n        throw new IllegalStateException(\n            \"Error handler is already closed, and may not be closed twice\");\n      }\n      closed = true;\n      PCollection<ErrorT> flattened;\n      if (errorCollections.isEmpty()) {\n        LOG.info(\"Empty list of error pcollections passed to ErrorHandler.\");\n        flattened = pipeline.apply(Create.empty(coder));\n      } else {\n        flattened = PCollectionList.of(errorCollections).apply(Flatten.pCollections());\n      }\n      LOG.debug(\n          \"{} error collections are being sent to {}\",\n          errorCollections.size(),\n          sinkTransform.getName());\n      String sinkTransformName = sinkTransform.getName();\n      sinkOutput =\n          flattened\n              .apply(","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/errorhandling/ErrorHandler.java#L127-L163","documentation":"ErrorHandler.close() throws IllegalStateException when called on an already-closed handler. Closing flattens registered error collections into the sink output once; a second close would re-finalize state, so Beam treats double-close as a programming error rather than idempotently succeeding.","triggerScenarios":"Calling close() twice on the same DefaultErrorHandler — commonly via try-with-resources plus a manual close() call, or a __exit__ path (Python interop / with-statement semantics) that closes the handler after user code already closed it.","commonSituations":"Combining with-statement usage with explicit close(); closing the handler in both an expand() helper and the caller; re-running a finalize method during retries of pipeline construction.","solutions":["Close the handler exactly once — remove duplicate close() calls.","Prefer try-with-resources and drop manual close() calls.","Track closed state in application code if multiple code paths may finalize the handler."],"exampleFix":"// before\ntry (ErrorHandler<BadRecord> h = errorHandler) {\n  ...\n  errorHandler.close(); // double close\n}\n// after\ntry (ErrorHandler<BadRecord> h = errorHandler) {\n  ... // close happens automatically once\n}","handlingStrategy":"type-guard","validationCode":"if (!closedOnce) { errorHandler.close(); closedOnce = true; }","typeGuard":"class CloseOnce<T> implements AutoCloseable {\n  private final ErrorHandler<T> delegate; private boolean closed = false;\n  CloseOnce(ErrorHandler<T> d){this.delegate=d;}\n  public void close(){ if(!closed){ delegate.close(); closed=true; } }\n}","tryCatchPattern":"try {\n  errorHandler.close();\n} catch (IllegalStateException e) {\n  LOG.warn(\"Handler already closed; ignoring\", e);\n}","preventionTips":["Use try-with-resources exclusively; never also call close() manually","Track closure with a boolean wrapper if multiple paths may close","Audit finalize/cleanup code paths for duplicate close calls"],"tags":["java","apache-beam","error-handling","illegal-state","double-close"],"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"}