apache/pulsar · error · RuntimeException

failed to get client token

Error message

failed to get client token

What it means

AuthenticationDataToken.getToken() invokes its tokenSupplier and wraps any Throwable in RuntimeException("failed to get client token", t). getToken backs getCommandData(), so every protocol command that needs the bearer token re-evaluates the supplier; any failure inside it (file read, secret lookup, NPE on a null supplier result) surfaces as this runtime exception.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/AuthenticationDataToken.java:64

    public Set<Map.Entry<String, String>> getHttpHeaders() {
        return this.headers.entrySet();
    }

    @Override
    public boolean hasDataFromCommand() {
        return true;
    }

    @Override
    public String getCommandData() {
        return getToken();
    }

    private String getToken() {
        try {
            return tokenSupplier.get();
        } catch (Throwable t) {
            throw new RuntimeException("failed to get client token", t);
        }
    }
}

View on GitHub (pinned to 820761864e)

Solutions

  1. Inspect the wrapped cause (getCause()) to find why the supplier failed (missing file, null token, secret lookup error).
  2. Ensure the token source is available and returns a valid non-blank JWT before/while the client runs.
  3. For file-based tokens, verify the token file path exists and is readable at runtime, not just at startup.
  4. Harden custom token suppliers to throw descriptive exceptions and never return null.

Example fix

// before
Supplier<String> supplier = () -> Files.exists(path) ? readToken(path) : null; // null -> NPE wrapped as this error
// after
Supplier<String> supplier = () -> {
    if (!Files.isReadable(path)) throw new IllegalStateException("token file missing: " + path);
    return readToken(path);
};
Defensive patterns

Strategy: try-catch

Validate before calling

Supplier<String> safeSupplier = () -> {
    String t = rawSupplier.get();
    if (t == null || t.isBlank()) throw new IllegalStateException("token supplier produced a blank token");
    return t;
};

Type guard

boolean isUsableToken(String t) { return t != null && t.split("\\.").length == 3; } // compact JWT

Try / catch

try {
    client = PulsarClient.builder().authentication(AuthenticationFactory.token(supplier))...create();
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("failed to get client token")) {
        log.error("token supplier failed: {}", e.getCause(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: The Supplier<String> passed to AuthenticationToken/AuthenticationDataToken throws: token file missing or unreadable, secret-manager lookup fails, supplier returns null and downstream code NPEs, or a static token string configured as invalid/blank causing parsing failure.

Common situations: Kubernetes secret rotated/deleted while the client is running; token file path from env var not set; vault/DynamicTokenSupplier outage; using AuthenticationToken with a function that returns null after expiry handling; authParams JSON missing the 'token' key so the supplier resolves to nothing.

Related errors


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