apache/flink · error · IOException

Resource guard was already closed.

Error message

Resource guard was already closed.

What it means

ResourceGuard is a close-guard that lets a resource owner wait for outstanding leases before closing a resource (typically used by checkpoint storage). acquireResource() throws this IOException when the guard has already been closed, meaning no new clients may start using the resource because shutdown is in progress or complete.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/ResourceGuard.java:66

    /** This flag indicated if it is still possible to acquire access to the resource. */
    private volatile boolean closed;

    public ResourceGuard() {
        this.lock = new SerializableObject();
        this.leaseCount = 0;
        this.closed = false;
    }

    /**
     * Acquired access from one new client for the guarded resource.
     *
     * @throws IOException when the resource guard is already closed.
     */
    public Lease acquireResource() throws IOException {

        synchronized (lock) {
            if (closed) {
                throw new IOException("Resource guard was already closed.");
            }

            ++leaseCount;
        }

        return new Lease();
    }

    /**
     * Releases access for one client of the guarded resource. This method must only be called after
     * a matching call to {@link #acquireResource()}.
     */
    private void releaseResource() {

        synchronized (lock) {
            --leaseCount;

            if (closed && leaseCount == 0) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Fix the lifecycle ordering so acquireResource() is called before close(), e.g. cancel the acquisition path (task cancellation) before triggering the guard's close.
  2. If racing with cancellation is expected, catch the IOException at the call site and treat it as a cancellation signal (abort the operation cleanly) rather than propagating it.
  3. Ensure only one component owns close() and that no code path (timer thread, async snapshot thread) tries to acquire after shutdown begins.

Example fix

// before
Lease lease = guard.acquireResource(); // may throw after close

// after
Lease lease;
try {
    lease = guard.acquireResource();
} catch (IOException e) {
    // resource is shutting down; abort this operation
    return;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    ResourceGuard.Lease lease = guard.acquireResource();
    // use resource
} catch (IOException e) {
    // guard closed: treat as shutdown/cancellation, abort this operation cleanly
}

Prevention

When it happens

Trigger: Calling acquireResource() on a ResourceGuard after close() was invoked, or racing with close(): another thread closed the guard between the check and the acquisition attempt inside the synchronized block.

Common situations: Concurrent checkpoint/state-backend code that acquires access to a snapshot stream or durable data set while a task or operator is being cancelled and the guard is closed; lifecycle bugs where a component is used after its shutdown method ran.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/92dd2e7e19823f8f. Report an issue: GitHub.