{"id":"2e659a107d2c1645","repo":"redis/redis","slug":"aeapiassociate-event-port-limit-exceeded","errorCode":null,"errorMessage":"aeApiAssociate: event port limit exceeded.","messagePattern":"aeApiAssociate: event port limit exceeded\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/ae_evport.c","lineNumber":148,"sourceCode":"        events |= POLLIN;\n    if (mask & AE_WRITABLE)\n        events |= POLLOUT;\n\n    if (evport_debug)\n        fprintf(stderr, \"%s: port_associate(%d, 0x%x) = \", where, fd, events);\n\n    rv = port_associate(portfd, PORT_SOURCE_FD, fd, events,\n        (void *)(uintptr_t)mask);\n    err = errno;\n\n    if (evport_debug)\n        fprintf(stderr, \"%d (%s)\\n\", rv, rv == 0 ? \"no error\" : strerror(err));\n\n    if (rv == -1) {\n        fprintf(stderr, \"%s: port_associate: %s\\n\", where, strerror(err));\n\n        if (err == EAGAIN)\n            fprintf(stderr, \"aeApiAssociate: event port limit exceeded.\");\n    }\n\n    return rv;\n}\n\nstatic int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {\n    aeApiState *state = eventLoop->apidata;\n    int fullmask, pfd;\n\n    if (evport_debug)\n        fprintf(stderr, \"aeApiAddEvent: fd %d mask 0x%x\\n\", fd, mask);\n\n    /*\n     * Since port_associate's \"events\" argument replaces any existing events, we\n     * must be sure to include whatever events are already associated when\n     * we call port_associate() again.\n     */\n    fullmask = mask | eventLoop->events[fd].mask;","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/redis/redis/blob/3acc0c49cf5ad2af9425d333e62728342dd6159b/src/ae_evport.c#L130-L166","documentation":"Logged (stderr) at src/ae_evport.c:148 as a diagnostic follow-up when port_associate failed specifically with errno == EAGAIN. On Solaris/illumos event ports, EAGAIN indicates the kernel's per-port association resource limit has been exhausted — there are too many fds concurrently associated with the event port. It is emitted immediately after the generic message in error 12 and, like it, ultimately causes the caller to abort(). The 'counter-intuitive' comment at ae_evport.c:237-242 notes EAGAIN is not retried because the limit is structural.","triggerScenarios":"Reached inside aeApiAssociate (ae_evport.c:125) only when port_associate returns -1 AND errno == EAGAIN (line 147). This happens when the number of fds actively associated with state->portfd exceeds the kernel's port association capacity. It can fire from any of the three call sites: aeApiAddEvent, aeApiDelEvent re-association, or the aeApiPoll re-association loop (lines 259-272) that bulk re-associates pending_fds before each port_getn.","commonSituations":"Setting maxclients higher than the illumos event-port association ceiling, running on a SmartOS/OmniOS zone with a small project.max-port-events rctl, or a fd leak that steadily grows the association count. Often appears after a traffic spike or after clients fail to disconnect cleanly, accumulating stale associations.","solutions":["Reduce maxclients to a value safely below the kernel's per-port association limit (check with 'prctl -n project.max-port-events' on the running project).","Raise the illumos resource cap: project.max-port-events (and related port rctls) via projmod / prctl / zone config, then restart Redis.","Investigate a fd leak — confirmed by 'pfiles <pid>' showing far more open fds than active clients — and fix the unclosed-connection path.","On a non-illumos target where event ports are not needed, rebuild Redis to select epoll/kqueue instead (the ae backend is chosen at compile time).","Restart the process to clear the saturated port, then monitor association growth to confirm the cap holds."],"exampleFix":"// before — EAGAIN logged once, callers abort()\nif (err == EAGAIN)\n    fprintf(stderr, \"aeApiAssociate: event port limit exceeded.\");\n// after — back off and lower the active association count before retrying\nif (err == EAGAIN) {\n    serverLog(LL_WARNING,\"event port limit exceeded; shedding and retrying\");\n    /* drop stale pending associations, then retry port_associate */\n    rv = port_associate(portfd, PORT_SOURCE_FD, fd, events,(void*)(uintptr_t)mask);\n}","handlingStrategy":"validation","validationCode":"// Pre-validate the fd count against the event-port association limit before associating.\nconst PORT_MAX_ASSOCIATIONS = 1024; // conservative; confirm against your evport build\nfunction assertWithinPortLimit(associatedCount, pending) {\n  if (associatedCount + pending > PORT_MAX_ASSOCIATIONS) {\n    throw new Error(`event port association limit would be exceeded (${associatedCount}+${pending})`);\n  }\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Track the count of fds currently associated with the port; reject new associations that would breach the documented limit.","If you must exceed the limit, shard across multiple event ports rather than relying on a single port.","On evport backends prefer fewer, long-lived connections (pooling) over churning many short-lived ones.","Read the platform's port_create/port_associate man page to get the real limit for your kernel before sizing."],"tags":["solaris","illumos","event-ports","resource-limit","eagain","event-loop"],"analyzedSha":"3acc0c49cf5ad2af9425d333e62728342dd6159b","analyzedAt":"2026-08-01T22:07:56.715Z","schemaVersion":2}