quarkusio/quarkus · error · SpiffeConnectionException
SPIFFE ID must not contain percent-encoded characters: ${spi
Error message
SPIFFE ID must not contain percent-encoded characters: ${spiffeId} What it means
SPIFFE IDs must not contain percent-encoded characters (%xx); SPIFFE URIs are plain UTF-8 and encoding would make IDs ambiguous. SpiffeValidator.validateSpiffeId rejects any ID containing '%' with SpiffeConnectionException.
Source
Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java:79
"Signing certificate SPIFFE ID must not have a path component: " + uriSan);
}
}
}
static void validateSpiffeId(String spiffeId) throws SpiffeConnectionException {
if (spiffeId == null || spiffeId.isEmpty()) {
throw new SpiffeConnectionException("SPIFFE ID must not be empty");
}
if (spiffeId.length() > MAX_SPIFFE_ID_LENGTH) {
throw new SpiffeConnectionException("SPIFFE ID exceeds maximum length of " + MAX_SPIFFE_ID_LENGTH
+ " bytes: " + spiffeId.length());
}
if (!spiffeId.startsWith(SPIFFE_URI_PREFIX)) {
throw new SpiffeConnectionException("SPIFFE ID must have 'spiffe://' scheme: " + spiffeId);
}
if (spiffeId.contains("%")) {
throw new SpiffeConnectionException("SPIFFE ID must not contain percent-encoded characters: " + spiffeId);
}
URI uri;
try {
uri = URI.create(spiffeId);
} catch (IllegalArgumentException e) {
throw new SpiffeConnectionException("SPIFFE ID is not a valid URI: " + spiffeId, e);
}
if (uri.getUserInfo() != null) {
throw new SpiffeConnectionException("SPIFFE ID must not contain userinfo: " + spiffeId);
}
if (uri.getPort() != -1) {
throw new SpiffeConnectionException("SPIFFE ID must not contain a port: " + spiffeId);
}
if (uri.getQuery() != null) {
throw new SpiffeConnectionException("SPIFFE ID must not contain a query: " + spiffeId);
}View on GitHub (pinned to e1c734241f)
Solutions
- Build the SPIFFE ID from raw, unencoded UTF-8 path segments joined with '/'.
- Remove URLEncoder/percent-encoding from the identity construction code.
- Sanitize or reject inputs containing '%' before forming the ID.
Example fix
// before String id = "spiffe://example.org/ns/" + URLEncoder.encode(ns, UTF_8); // after String id = "spiffe://example.org/ns/" + ns; // ns must not contain reserved chars
Defensive patterns
Strategy: validation
Validate before calling
if (spiffeId.indexOf('%') >= 0) {
throw new IllegalStateException("SPIFFE ID must not be percent-encoded: " + spiffeId);
} Try / catch
try {
connection.establish();
} catch (SpiffeConnectionException e) {
if (e.getMessage().contains("percent-encoded")) {
log.error("SPIFFE ID was URL-encoded during construction; use raw segments", e);
}
throw e;
} Prevention
- Never use URLEncoder for SPIFFE ID path segments
- Join raw, validated segments with '/'
- Reject '%' in identity-related user input early
When it happens
Trigger: An ID built from URL-encoded components, e.g. URLEncoder.encode applied to path segments producing spiffe://example.org/ns/d%2Fdefault, then passed to validation.
Common situations: Reusing URL-building utilities (URLEncoder/UriBuilder) to construct SPIFFE IDs; embedding user-controlled or encoded path data in identity templates.
Related errors
- Audiences must not be empty
- SPIFFE ID must not be empty
- SPIFFE ID exceeds maximum length of 2048 bytes: ${length}
- SPIFFE ID must have 'spiffe://' scheme: ${spiffeId}
- SPIFFE ID is not a valid URI: ${spiffeId}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5b155e3c20eaf622.
Report an issue: GitHub.