apache/pulsar · warning · BookieException.MetadataStoreException

Interrupted deleting cookie for bookie ${bookieId}

Error message

Interrupted deleting cookie for bookie ${bookieId}

What it means

removeCookie performs a blocking store.delete(path, expectedVersion).get(timeout) on the asynchronous MetadataStore. If the waiting thread is interrupted, the manager restores the interrupt flag and throws BookieException.MetadataStoreException('Interrupted deleting cookie for bookie <bookieId>'). This happens during cookie cleanup (bookie decommission or format) and indicates the thread was interrupted, not that the delete itself failed or the cookie is missing.

Source

Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarRegistrationManager.java:281

            LongVersion version = new LongVersion(res.get().getStat().getVersion());
            return new Versioned<>(res.get().getValue(), version);
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
            throw new BookieException.MetadataStoreException(ie);
        } catch (ExecutionException | TimeoutException e) {
            throw new BookieException.MetadataStoreException(e);
        }
    }

    @Override
    public void removeCookie(BookieId bookieId, Version version) throws BookieException {
        String path = this.cookiePath + "/" + bookieId;
        try {
            store.delete(path, Optional.of(((LongVersion) version).getLongVersion()))
                    .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BookieException.MetadataStoreException("Interrupted deleting cookie for bookie " + bookieId, e);
        } catch (ExecutionException e) {
            if (e.getCause() instanceof MetadataStoreException.NotFoundException) {
                throw new BookieException.CookieNotFoundException(bookieId.toString());
            } else {
                throw new BookieException.MetadataStoreException("Failed to delete cookie for bookie " + bookieId);
            }
        } catch (TimeoutException ex) {
            throw new BookieException.MetadataStoreException("Failed to delete cookie for bookie " + bookieId);
        }

        log.info().attr("cookiePath", cookiePath).attr("bookieId", bookieId).log("Removed cookie for bookie");
    }

    @Override
    public boolean prepareFormat() throws Exception {
        boolean ledgerRootExists = store.exists(ledgersRootPath).get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
        boolean availableNodeExists = store.exists(bookieRegistrationPath).get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
        // Create ledgers root node if not exists

View on GitHub (pinned to 820761864e)

Solutions

  1. Respect the interrupt: stop the current decommission/cleanup task; the interrupt flag has been re-set so downstream code will also see it.
  2. Re-run the decommission command after the environment is stable — removeCookie is safe to retry if the cookie still exists.
  3. Fix lifecycle ordering so cookie deletion completes before the executor/process begins shutting down.
  4. If the metadata store is stalling (which makes long blocking waits likely), resolve the store latency first, then retry.

Example fix

// before
try {
    regManager.removeCookie(bookieId, version);
} catch (BookieException e) {
    log.info("ignoring", e); // swallows interrupt
}

// after
try {
    regManager.removeCookie(bookieId, version);
} catch (BookieException.MetadataStoreException e) {
    if (Thread.currentThread().isInterrupted()) {
        Thread.currentThread().interrupt();
        return; // abort cleanup, retry later
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    regManager.removeCookie(bookieId, version);
} catch (BookieException.MetadataStoreException e) {
    if (Thread.currentThread().isInterrupted()) {
        // abort decommission gracefully; safe to rerun later
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: The thread blocked in removeCookie's .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS) is interrupted — typically during bookie shutdown/decommission while deleting the cookie, or a canceled admin/format task interrupting the worker thread.

Common situations: Decommissioning a bookie (bin/bookkeeper shell decommission) while the client/process is being shut down concurrently; MetadataStoreExpirer or format tooling run under an executor that gets shutDownNow; operator Ctrl-C during a long-running metadata-store stall.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/19122b3d35c965ad. Report an issue: GitHub.