aeron-io/aeron · error · IllegalArgumentException
EINVAL
EINVAL
Error message
Unknown correlation id
What it means
Thrown by ExclusivePublication::findDestinationResponse(correlationId) when the given correlation id is not present in the publication's m_pendingDestinations map. This means no async addDestination/removeDestination call registered with that id, or the response was already consumed. The library treats looking up an unknown correlation id as an invalid-argument error rather than returning false.
Solutions
- Store the correlationId returned by ExclusivePublication::addDestination/removeDestination and only query with that exact value.
- Treat findDestinationResponse as single-shot: after the entry resolves, do not call it again with the same id.
- Check control-flow so the id passed is from the current publication's pending set, not another publication's or a Subscription's.
- Wrap the call in try-catch for IllegalArgumentException if correlation bookkeeping might be stale, and re-issue the add/removeDestination instead.
Example fix
// before
long id = someGuessedId;
publication.findDestinationResponse(id); // not in m_pendingDestinations
// after
long id = publication.addDestination("aeron:udp?endpoint=localhost:40456");
if (publication.findDestinationResponse(id)) { /* done, do not reuse id */ } Defensive patterns
Strategy: validation
Validate before calling
std::unordered_set<long> pendingIds; long id = publication.addDestination(uri); pendingIds.insert(id); // before calling: if (!pendingIds.count(id)) skip or re-add;
Try / catch
try {
if (publication.findDestinationResponse(id)) { pendingIds.erase(id); }
} catch (const aeron::util::IllegalArgumentException&) {
log("stale correlation id; re-adding destination");
id = publication.addDestination(uri);
} Prevention
- Store the correlationId returned by addDestination/removeDestination
- Consume each id exactly once; erase after resolution
- Do not share ids between ExclusivePublication instances
- Re-register destinations after restart instead of replaying old ids
When it happens
Trigger: Passing a correlationId that was never returned from addDestination/removeDestination, calling findDestinationResponse twice with the same id, or querying after the pending entry was resolved and erased.
Common situations: Application code that reuses or guesses correlation ids, polls for a destination response after a prior successful poll already consumed the entry, or loses track of the ids returned by async add/removeDestination.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/ddbee2c4d523502f.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-client/src/main/cpp_wrapper/ExclusivePublication.h:774
*
* - If the correlationId is unknown, then an exception is thrown.
* - If the media driver has not answered the add/remove command, then a false is returned.
* - If the media driver has successfully added or removed the destination then true is returned.
* - If the media driver has returned an error, this method will throw the error returned.
*
* @see Publication::addDestination
* @see Publication::removeDestination
*
* @param correlationId of the add/remove command returned by Publication::addDestination
* or Publication::removeDestination
* @return true for added or false if not.
*/
bool findDestinationResponse(std::int64_t correlationId)
{
auto search = m_pendingDestinations.find(correlationId);
if (search == m_pendingDestinations.end())
{
throw IllegalArgumentException("Unknown correlation id", SOURCEINFO, EINVAL);
}
auto async = search->second;
try
{
bool result = findDestinationResponse(async);
if (result)
{
m_pendingDestinations.erase(correlationId);
}
return result;
}
catch (...)
{
m_pendingDestinations.erase(correlationId);
throw;
}
}View on GitHub (pinned to 6d60124e15)