{"record":{"id":"dd97b6b96a24cd7d","repo":"nginx/nginx","slug":"ngx-log-warn-dd97b6","errorCode":"NGX_LOG_WARN","errorMessage":"kqueue change list is filled up","messagePattern":"kqueue change list is filled up","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/event/modules/ngx_kqueue_module.c","lineNumber":415,"sourceCode":"    return rc;\n}\n\n\nstatic ngx_int_t\nngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)\n{\n    struct kevent     *kev;\n    struct timespec    ts;\n    ngx_connection_t  *c;\n\n    c = ev->data;\n\n    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,\n                   \"kevent set event: %d: ft:%i fl:%04Xi\",\n                   c->fd, filter, flags);\n\n    if (nchanges >= max_changes) {\n        ngx_log_error(NGX_LOG_WARN, ev->log, 0,\n                      \"kqueue change list is filled up\");\n\n        ts.tv_sec = 0;\n        ts.tv_nsec = 0;\n\n        if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)\n            == -1)\n        {\n            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, \"kevent() failed\");\n            return NGX_ERROR;\n        }\n\n        nchanges = 0;\n    }\n\n    kev = &change_list[nchanges];\n\n    kev->ident = c->fd;","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/nginx/nginx/blob/3f6f7824d4e2eb1ac37dec76683d525ac0ff521c/src/event/modules/ngx_kqueue_module.c#L397-L433","documentation":"ngx_kqueue_set_event() buffers change operations in change_list and submits them lazily with the next kevent() wait. When nchanges reaches max_changes (sized by the kqueue_changes directive, default 512), it logs this WARN and immediately flushes the list with a zero-timeout kevent(), then queues the new change, so no functionality is lost. It is a batching/performance hint: frequent occurrences mean the buffer is too small for the connection churn.","triggerScenarios":"Bursts of event add/del/enable operations between event-loop iterations (mass connection setup/teardown, accept storms, many timers) exceeding kqueue_changes, triggering the forced flush path at the top of ngx_kqueue_set_event().","commonSituations":"Benchmark or traffic spikes with thousands of new connections per second; configurations with many short-lived upstream connections; default kqueue_changes 512 left untouched after worker_connections was raised.","solutions":["Raise the buffer: events { kqueue_changes 4096; } sized above peak concurrent event churn.","Re-run the same load and confirm the warnings disappear.","If warnings persist, profile what generates the churn (aggressive upstream reconnects, tiny keepalive timeouts).","No correctness action needed: nginx already flushed and continued."],"exampleFix":"# before\nevents { worker_connections 4096; }   # kqueue_changes defaults to 512\n\n# after\nevents {\n    worker_connections 4096;\n    kqueue_changes 4096;   # buffer above peak churn so forced flushes stop\n}","handlingStrategy":"validation","validationCode":"# nginx.conf: size the change buffer above peak event churn before load arrives\nevents {\n    kqueue_changes 4096;   # default 512; raise when this warning appears under load\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Load-test to measure event churn; set kqueue_changes above peak concurrent operations","Remember the warning is non-fatal: nginx flushes and continues - tune for throughput","Re-check the setting after adding modules that create many ephemeral connections"],"tags":["nginx","kqueue","kqueue-changes","tuning","performance"],"backgroundTag":"event-change-buffer-overflow","analyzedSha":"3f6f7824d4e2eb1ac37dec76683d525ac0ff521c","analyzedAt":"2026-08-22T03:09:46.447Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}