aeron-io/aeron · error · IllegalArgumentException
EINVAL
EINVAL
Error message
Unknown correlation id
What it means
Thrown by Publication::findDestinationResponse(correlationId) when the correlation id is not found among the publication's pending destinations (m_pendingDestinations), while holding the admin lock. Each async addDestination/removeDestination registers an id that is consumed exactly once; querying an unregistered or already-resolved id throws. The library signals this as EINVAL rather than a not-found return value.
Solutions
- Keep a one-to-one record of ids returned by addDestination/removeDestination and discard each id after its first successful findDestinationResponse.
- Confirm the id belongs to this exact Publication instance (not a Subscription or ExclusivePublication).
- After a restart, re-issue add/removeDestination rather than reusing persisted correlation ids.
- Guard with try-catch on IllegalArgumentException and fall back to re-registering the destination.
Example fix
// before
publication.findDestinationResponse(id);
// ... later
publication.findDestinationResponse(id); // second poll of same id throws
// after
if (publication.findDestinationResponse(id)) { id = -1; /* mark consumed */ } Defensive patterns
Strategy: validation
Validate before calling
std::unordered_map<long, std::string> pending;
long id = publication.addDestination(uri);
pending[id] = uri;
// before querying: if (!pending.count(id)) { /* re-add instead */ } Try / catch
try {
if (publication.findDestinationResponse(id)) { pending.erase(id); }
} catch (const aeron::util::IllegalArgumentException&) {
log("unknown correlation id; re-registering destination");
} Prevention
- Track each addDestination/removeDestination id and retire it after first resolution
- Never poll the same correlation id twice
- Keep Publication/Subscription/ExclusivePublication id namespaces separate
- After restart, re-issue destination commands rather than reusing persisted ids
When it happens
Trigger: Calling findDestinationResponse with an id not obtained from this Publication's addDestination/removeDestination, polling twice with the same id, or passing a Subscription or ExclusivePublication id to a different object.
Common situations: Correlation-id bookkeeping bugs in application code, duplicate polling loops that never clear consumed ids, or IDs persisted and replayed after a restart where pending state is gone.
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/0c7de099cf5da29f.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-client/src/main/cpp_wrapper/Publication.h:755
* - 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)
{
std::lock_guard<std::recursive_mutex> lock(m_adminLock);
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)