apache/beam · error · IllegalArgumentException
No Op handler should not be closed. This implies this IO is
Error message
No Op handler should not be closed. This implies this IO is misconfigured.
What it means
NoOpErrorHandler.isClosed always throws IllegalArgumentException because a No-Op handler represents a deliberately absent error handler. Querying its lifecycle state means an IO asked for error-handler metadata it should never need, indicating the IO was misconfigured to use the No-Op handler as a real one.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/errorhandling/ErrorHandler.java:228
super(sinkTransform, pipeline, BadRecord.getCoder(pipeline));
}
}
/**
* A default, placeholder error handler that exists to allow usage of .addErrorCollection()
* without effects. This enables more simple codepaths without checking for whether the user
* configured an error handler or not.
*/
@Internal
class DefaultErrorHandler<ErrorT, OutputT extends POutput>
implements ErrorHandler<ErrorT, OutputT> {
@Override
public void addErrorCollection(PCollection<ErrorT> errorCollection) {}
@Override
public boolean isClosed() {
throw new IllegalArgumentException(
"No Op handler should not be closed. This implies this IO is misconfigured.");
}
@Override
public @Nullable OutputT getOutput() {
throw new IllegalArgumentException(
"No Op handler has no output. This implies this IO is misconfigured.");
}
@Override
public void close() {
throw new IllegalArgumentException(
"No Op handler should not be closed. This implies this IO is misconfigured.");
}
}
}
View on GitHub (pinned to 12126d8942)
Solutions
- Use a real (Default)ErrorHandler if lifecycle queries are needed.
- Change the IO configuration to supply a genuine error handler.
- Remove/guard the isClosed() polling in generic code so it skips No-Op handlers.
Example fix
// before
if (errorHandler.isClosed()) { ... } // throws for NoOp
// after
if (!(errorHandler instanceof ErrorHandler.NoOpErrorHandler) && errorHandler.isClosed()) { ... } Defensive patterns
Strategy: type-guard
Validate before calling
if (errorHandler instanceof ErrorHandler.NoOpErrorHandler) { /* skip lifecycle checks */ } Type guard
boolean isRealHandler(ErrorHandler<?> h) {
return !(h instanceof ErrorHandler.NoOpErrorHandler);
} Try / catch
try {
errorHandler.isClosed();
} catch (IllegalArgumentException e) {
LOG.warn("No-Op handler queried for lifecycle; IO misconfigured", e);
} Prevention
- Never pass ErrorHandler.getNoOpHandler() where lifecycle management is expected
- Check the handler type before generic lifecycle plumbing runs
- Configure a real handler for IOs that query handler state
When it happens
Trigger: An IO connector or framework code calls isClosed() on ErrorHandler.getNoOpHandler() — e.g. lifecycle checks in generic error-handler plumbing applied to a pipeline built without a real error handler.
Common situations: Passing the No-Op singleton where a DefaultErrorHandler is expected; generic code paths that poll isClosed() on any ErrorHandler implementation; refactor after removing a real handler but leaving polling logic.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- No Op handler has no output. This implies this IO is misconf
- Encountered Bad Record:
- Error collections cannot be added after Error Handler is clo
- ErrorHandler must be finalized before the output can be retu
- Error handler is already closed, and may not be closed twice
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/b2ed5deb1c28a9d5.
Report an issue: GitHub.