aeron-io/aeron · error · ConfigurationException
invalid recordingId
Error message
invalid recordingId
What it means
conclude() validates that recordingId is non-negative (0 is a valid recording id). A negative value means the recording id was never assigned (left at Aeron.NULL_VALUE = -1) or was corrupted, so the archive would be asked to replay a nonexistent recording. A ConfigurationException naming the offending id is thrown.
Solutions
- Obtain a valid recordingId (>= 0) from the archive (e.g. via AeronArchive.startRecording or RecordingDescriptorPoller) and set it before conclude().
- Guard your code: only construct the persistent subscription after recordingId is known.
- If you intended to follow a live recording from its start, ensure recording started successfully and its id was captured in the RecordingSignal/started event.
Example fix
// before
ctx.recordingId(Aeron.NULL_VALUE); // or never set
ctx.conclude(); // throws: invalid recordingId -1
// after
final long recordingId = archive.startRecording(
"aeron:udp?endpoint=localhost:10000", 5, SourceLocation.LOCAL, true);
ctx.recordingId(recordingId);
ctx.conclude(); Defensive patterns
Strategy: validation
Validate before calling
if (recordingId < 0) {
throw new IllegalArgumentException("recordingId must be >= 0, got " + recordingId);
} Try / catch
try {
ctx.conclude();
} catch (ConfigurationException e) {
// recordingId not yet known: wait for RecordingSignal/started event
} Prevention
- Only construct the persistent subscription after receiving a valid recordingId from startRecording or a descriptor poller.
- Treat Aeron.NULL_VALUE as 'unknown' and never pass it through to the subscription.
When it happens
Trigger: conclude() called while recordingId < 0, typically still at the Aeron.NULL_VALUE default because no recordingId(...) setter was invoked or the caller passed a sentinel/'unknown' value.
Common situations: Starting a persistent subscription before the recording has actually started (recordingId not yet known); hardcoding -1 as 'auto'; a failed listRecording/RecordingDescriptorPoller lookup returning a sentinel that is forwarded unchanged.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid startPosition
- aeronArchiveContext must be set
- Archive.Context.controlChannel must be set
- Archive.Context.controlChannel must be UDP media: uri=
- Archive.Context.recordingEventsChannel must be set if…
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/aafb14d9b9720d7a.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/client/PersistentSubscription.java:1717
if (Aeron.NULL_VALUE == replayStreamId)
{
throw new ConfigurationException("replayStreamId must be set");
}
if (null == aeronArchiveContext)
{
throw new ConfigurationException("aeronArchiveContext must be set");
}
if (null == listener)
{
listener = new NoOpPersistentSubscriptionListener();
}
if (0 > recordingId)
{
throw new ConfigurationException("invalid recordingId " + recordingId);
}
if (FROM_LIVE > startPosition)
{
throw new ConfigurationException("invalid startPosition " + startPosition);
}
final ChannelUri replayChannelUri = ChannelUri.parse(replayChannel);
if (replayChannelUri.hasControlModeResponse())
{
final String controlRequestChannel = aeronArchiveContext.controlRequestChannel();
if (null != controlRequestChannel &&
!replayChannelUri.isIpc() == ChannelUri.parse(controlRequestChannel).isIpc()
)
{
throw new ConfigurationException(
"Channel media type mismatch. " +View on GitHub (pinned to 6d60124e15)