aeron-io/aeron · error · IllegalStateException
empty key not allowed at index
Error message
empty key not allowed at index <i> in <uri>
What it means
ChannelUri.parse() tokenizes an Aeron channel URI string with a small state machine. While parsing the query-parameter section, when it encounters '=' it requires that a non-empty key has accumulated; if nothing was accumulated (e.g. the URI starts a param with '=') it throws this IllegalStateException to reject a malformed URI.
Solutions
- Inspect the URI string at the reported index <i> and fix the malformed parameter so every '=' has a non-empty key before it
- Build URIs with ChannelUriStringBuilder (with validate()) instead of string concatenation
- Wrap parse() in try-catch for IllegalStateException if URIs come from external input, and surface a clear config error
Example fix
// before
ChannelUri uri = ChannelUri.parse("aeron:udp?endpoint=localhost:40456|=1");
// after
ChannelUri uri = ChannelUri.parse("aeron:udp?endpoint=localhost:40456|ttl=1"); Defensive patterns
Strategy: validation
Validate before calling
static void validateNoEmptyKeys(String uri) {
int q = uri.indexOf('?');
if (q < 0) return;
for (String p : uri.substring(q + 1).split("\\|")) {
int eq = p.indexOf('=');
if (eq == 0) throw new IllegalArgumentException("empty key in: " + uri);
}
} Type guard
static boolean hasWellFormedParams(String uri) {
int q = uri.indexOf('?');
if (q < 0) return true;
for (String p : uri.substring(q + 1).split("\\|")) {
if (p.indexOf('=') <= 0) return false;
}
return true;
} Try / catch
try {
ChannelUri uri = ChannelUri.parse(channelUri);
} catch (IllegalStateException e) {
throw new IllegalArgumentException("Malformed Aeron channel URI: " + channelUri, e);
} Prevention
- Build URIs with ChannelUriStringBuilder rather than string concatenation
- Never emit an empty parameter name; guard generated params for null/empty names
- Validate URIs from external config at startup, before any publication is created
When it happens
Trigger: Calling ChannelUri.parse() on a URI whose params section contains an empty key, e.g. "aeron:udp?endpoint=localhost:40456|=value|alias=x" or "aeron:udp?|k=v" — a '=' is reached with an empty key builder.
Common situations: Programmatically building channel URIs with string concatenation where a param name is empty or an extra '|' or stray '=' sneaks in; hand-edited configuration where a parameter name was deleted but the '=' remained.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- invalid end of key at index
- no more input found, state=
- media type is mandatory
- value exceeds maximum permitted: value=
- must be a number
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/f3d5e482ad143058.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-client/src/main/java/io/aeron/ChannelUri.java:439
break;
case ':':
case '|':
case '=':
throw new IllegalArgumentException(
"encountered '" + c + "' within media definition at index " + i + " in " + uri);
default:
builder.append(c);
}
break;
case PARAMS_KEY:
if (c == '=')
{
if (builder.isEmpty())
{
throw new IllegalStateException("empty key not allowed at index " + i + " in " + uri);
}
key = builder.toString();
builder.setLength(0);
state = State.PARAMS_VALUE;
}
else
{
if (c == '|')
{
throw new IllegalStateException("invalid end of key at index " + i + " in " + uri);
}
builder.append(c);
}
break;
case PARAMS_VALUE:
if (c == '|')
{View on GitHub (pinned to 6d60124e15)