{"record":{"id":"d4eccd108078a553","repo":"joewalnes/websocketd","slug":"too-many-forks-active","errorCode":null,"errorMessage":"too many forks active","messagePattern":"too many forks active","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libwebsocketd/http.go","lineNumber":26,"sourceCode":"import (\n\t\"errors\"\n\t\"fmt\"\n\t\"html\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cgi\"\n\t\"net/textproto\"\n\t\"net/url\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/gorilla/websocket\"\n)\n\nvar ErrForkNotAllowed = errors.New(\"too many forks active\")\n\nvar upgradeRe = regexp.MustCompile(`(?i)(^|[,\\s])Upgrade($|[,\\s])`)\n\n// WebsocketdServer presents http.Handler interface for requests libwebsocketd is handling.\ntype WebsocketdServer struct {\n\tConfig   *Config\n\tLog      *LogScope\n\tforks    chan byte\n\thostname string // cached os.Hostname(), computed once at startup\n}\n\n// NewWebsocketdServer creates WebsocketdServer struct with pre-determined config, logscope and maxforks limit\nfunc NewWebsocketdServer(config *Config, log *LogScope, maxforks int) *WebsocketdServer {\n\thostname, err := os.Hostname()\n\tif err != nil {\n\t\thostname = \"UNKNOWN\"\n\t}\n\tmux := &WebsocketdServer{","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/joewalnes/websocketd/blob/7a8683dc7f9778dc615945aaed2a8dc77290227b/libwebsocketd/http.go#L8-L44","documentation":"ErrForkNotAllowed is returned by WebsocketdServer.noteForkCreated when the number of concurrently running child processes has reached the configured fork limit (--maxforks). It prevents the server from spawning more processes than allowed.","triggerScenarios":"noteForkCreated (libwebsocketd/http.go:331) is called in the default branch of its internal counter check once the active-fork counter is at the maximum; each new client connection that would spawn a process while the limit is hit gets this error.","commonSituations":"Too many simultaneous WebSocket clients for the configured --maxforks value; leaked/hung child scripts that never exit consume fork slots; load spikes from reconnecting clients.","solutions":["Raise the fork limit with --maxforks (or set it appropriately for expected concurrency)","Investigate child processes that hang and never release their fork slot","Add client-side backoff/retry with delay instead of immediate reconnect loops","Scale horizontally: run more websocketd instances behind a load balancer"],"exampleFix":"// before\nwebsocketd --port=8080 --maxforks=2 ./worker.sh\n// after\nwebsocketd --port=8080 --maxforks=100 ./worker.sh","handlingStrategy":"retry","validationCode":"// check your client's expected concurrency vs --maxforks before deploying\n// e.g. maxConcurrentClients must be <= --maxforks","typeGuard":null,"tryCatchPattern":"// reconnect with exponential backoff on close\nws.onclose = () => setTimeout(connect, Math.min(30000, 1000 * 2 ** attempt++));","preventionTips":["Size --maxforks at or above expected peak concurrency","Monitor for child processes that hang and never exit (they hold fork slots)","Use reconnect backoff so retry storms do not exhaust the fork budget"],"tags":["websocket","process-limits","concurrency"],"backgroundTag":"fork-limit-exceeded","analyzedSha":"7a8683dc7f9778dc615945aaed2a8dc77290227b","analyzedAt":"2026-09-03T13:52:22.309Z","contentChangedAt":"2026-09-03T13:52:22.309Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}