apache/pulsar · error · RuntimeException
Failed to read token from file
Error message
Failed to read token from file
What it means
TokenAuthenticationV5 supports reading the client token from a file:// URI. The file-backed token supplier reads all bytes of the file on each get(); an IOException (missing file, permissions, directory instead of file) is rethrown as a RuntimeException with this message, wrapping the original IOException.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/v5/TokenAuthenticationV5.java:135
}
}
/** A supplier reading the token from a file on every call, so a rotated token is picked up. */
public static final class FileTokenSupplier implements Supplier<String>, Serializable {
private static final long serialVersionUID = 3160666668166028760L;
private final URI uri;
public FileTokenSupplier(final URI uri) {
this.uri = uri;
}
@Override
public String get() {
try {
return new String(Files.readAllBytes(Paths.get(uri)), StandardCharsets.UTF_8).trim();
} catch (IOException e) {
throw new RuntimeException("Failed to read token from file", e);
}
}
}
private final Supplier<String> tokenSupplier;
// Late-bound at initializeAsync(...): the client's bounded blocking executor, onto which the token()
// read is off-loaded so a file-backed supplier (Files.readAllBytes) never runs on the Netty event loop
// (PIP-478). Null when used outside a client, in which case the read runs inline.
private transient volatile Executor blockingExecutor;
/**
* @param tokenSupplier supplies the current token on each call (enables refresh without rebuild)
*/
public TokenAuthenticationV5(Supplier<String> tokenSupplier) {
this.tokenSupplier = tokenSupplier;
}
View on GitHub (pinned to 820761864e)
Solutions
- Verify the token file path exists and is readable by the process user before starting the client (ls/permissions).
- Fix the URI in the auth configuration (token file parameter) to the correct absolute path.
- In Kubernetes, confirm the projected volume/secret is mounted and populated before the client starts; add an initContainer wait if needed.
- If tokens rotate by replacement, ensure the path always resolves (symlink swap, not delete+create).
Example fix
// before AuthParams: token:file:///etc/pulsar/token (file missing) // after AuthParams: token:file:///var/run/secrets/pulsar/token (verified mounted & readable)
Defensive patterns
Strategy: try-catch
Validate before calling
java.nio.file.Path p = java.nio.file.Path.of(uri.getPath());
if (!java.nio.file.Files.isRegularFile(p) || !java.nio.file.Files.isReadable(p)) {
throw new IllegalStateException("token file missing or unreadable: " + p);
} Try / catch
try {
String token = tokenSupplier.get();
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().equals("Failed to read token from file")) {
// check path/mount/permissions, then re-init auth
} else throw e;
} Prevention
- Validate the token file exists and is readable at startup, before creating the client.
- In Kubernetes, gate client startup on the projected secret being present (initContainer or readiness check).
- Rotate token files atomically (symlink swap) so a reader never sees a missing path.
When it happens
Trigger: Configuring authentication with tokenFromFile / a file: URI where the path does not exist, is not readable, or is a directory; the token file being deleted or rotated out from under a running client that calls get() lazily.
Common situations: Kubernetes secret mounts not yet projected at client startup; wrong path in authParams (typos, container vs host paths); file permissions changed after deployment; token file removed by a secret rotation job.
Related errors
- failed to get client token
- Timeout during mark-delete operation
- Timeout during clear backlog operation
- Timeout during skip messages operation
- Timeout during delete operation
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/3da0edb87058cdc6.
Report an issue: GitHub.