apache/pulsar · error · IOException

Illegal base64 character or Key file ${keyConfUrl} doesn't e

Error message

Illegal base64 character or Key file ${keyConfUrl} doesn't exist

What it means

readKeyFromUrl treats the configured value as: a file path/URL, or if it looks like pure base64, inline base64 key material. When the value is base64-shaped but Decoders.BASE64.decode still fails (illegal characters after the cheap isBase64 check), it wraps the DecodingException in this IOException.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/utils/AuthTokenUtils.java:131

                if (keyConfUrl.startsWith("file:")) {
                    keyConfUrl = keyConfUrl.trim();
                }
                return IOUtils.toByteArray(URL.createURL(keyConfUrl));
            } catch (IOException e) {
                throw e;
            } catch (Exception e) {
                throw new IOException(e);
            }
        } else if (Files.exists(Paths.get(keyConfUrl))) {
            // Assume the key content was passed in a valid file path
            return Files.readAllBytes(Paths.get(keyConfUrl));
        } else if (Base64.isBase64(keyConfUrl.getBytes())) {
            // Assume the key content was passed in base64
            try {
                return Decoders.BASE64.decode(keyConfUrl);
            } catch (DecodingException e) {
                String msg = "Illegal base64 character or Key file " + keyConfUrl + " doesn't exist";
                throw new IOException(msg, e);
            }
        } else {
            String msg = "Secret/Public Key file " + keyConfUrl + " doesn't exist";
            throw new IllegalArgumentException(msg);
        }
    }
}

View on GitHub (pinned to 820761864e)

Solutions

  1. Re-encode the key with standard base64 (no whitespace, no newlines) and paste it as a single line.
  2. If you meant a file, check the path: the file must exist, otherwise this code path wouldn't be chosen — verify no stray characters make the path look like base64.
  3. Decode the string yourself with `Base64.getDecoder().decode()` in a shell/test to find the offending character.

Example fix

// before
String keyConfUrl = "MIIBIjANBgkq...\n  more=="; // embedded whitespace/newlines
// after
String keyConfUrl = key.replace("\n", "").replace(" ", "").trim(); // single clean base64 line
Defensive patterns

Strategy: validation

Validate before calling

String clean = value.replaceAll("\\s", "");
if (!clean.matches("[A-Za-z0-9+/]*={0,2}")) throw new IllegalArgumentException("not clean base64");
java.util.Base64.getDecoder().decode(clean); // strict round-trip check

Type guard

boolean isCleanBase64(String s) { return s != null && s.replaceAll("\\s", "").matches("[A-Za-z0-9+/]+={0,2}"); }

Try / catch

try { byte[] key = AuthTokenUtils.readKeyFromUrl(cfg); } catch (IOException e) { throw new IllegalArgumentException("tokenSecretKey value is neither a valid file nor valid base64: " + e.getMessage(), e); }

Prevention

When it happens

Trigger: Setting tokenSecretKey/tokenPublicKey to an inline value that starts out base64-like (passes Base64.isBase64 on getBytes) but contains characters the strict decoder rejects — e.g. whitespace/newlines, URL-encoded characters, or mixed encodings.

Common situations: YAML/properties value with line wrapping or trailing newline inside the base64 secret; quoting issues that inject spaces; using a `data:` URL or `file:` prefix in a value that was meant to be inline base64.

Related errors


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